diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bc3c076f39..c061c95fff 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -13,3 +13,19 @@ updates: schedule: interval: "monthly" open-pull-requests-limit: 10 + groups: + pytest: + patterns: + - "pytest*" + - "hypothesis" + pyinstaller: + patterns: + - "pyinstaller*" + mypy: + patterns: + - "types-*" + - "mypy" + openssl: + patterns: + - "pyopenssl" + - "cryptography" diff --git a/.github/node-version.txt b/.github/node-version.txt index 8351c19397..3c032078a4 100644 --- a/.github/node-version.txt +++ b/.github/node-version.txt @@ -1 +1 @@ -14 +18 diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 8ee552c49e..c2ae2daec4 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -15,16 +15,26 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: install-pinned/ruff@0e35bc58bd73769469284df9e1f8898daeea8768 - - run: ruff --fix-only . + - uses: actions/setup-python@v5 + with: + python-version-file: .github/python-version.txt + - run: pip install -e .[dev] + - run: ruff check --fix-only . - run: ruff format . - - name: Run prettier - run: | - npm ci - npm run prettier + - run: web/gen/all + + - uses: actions/setup-node@v4 + with: + node-version-file: .github/node-version.txt + - run: npm ci + working-directory: web + - run: npm run eslint + working-directory: web + continue-on-error: true + - run: npm run prettier working-directory: web - uses: mhils/add-pr-ref-in-changelog@main - - uses: autofix-ci/action@d3e591514b99d0fca6779455ff8338516663f7cc + - uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5e7e68e4b3..4b3c4fa1af 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,6 +5,7 @@ on: branches: - '**' - '!dependabot/**' + - '!*-patch-*' pull_request: merge_group: workflow_dispatch: @@ -18,22 +19,22 @@ concurrency: jobs: lint: - uses: mhils/workflows/.github/workflows/python-tox.yml@main + uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e lint filename-matching: - uses: mhils/workflows/.github/workflows/python-tox.yml@main + uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e filename_matching mypy: - uses: mhils/workflows/.github/workflows/python-tox.yml@main + uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e mypy individual-coverage: - uses: mhils/workflows/.github/workflows/python-tox.yml@main + uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e individual_coverage @@ -57,7 +58,7 @@ jobs: with: persist-credentials: false fetch-depth: 0 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.py }} - run: pip install tox @@ -70,49 +71,57 @@ jobs: # run tests with loopback only. We need to sudo for unshare, which means we need an absolute path for tox. sudo unshare --net -- sh -c "ip link set lo up; $(which tox) -e py" if: matrix.os == 'ubuntu-latest' - - uses: mhils/better-codecov-action@main + - uses: codecov/codecov-action@v4 with: - arguments: '--file ./coverage.xml --name ${{ matrix.os }}' + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage.xml + + test-old-dependencies: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version-file: .github/python-version.txt + - run: pip install tox-uv + - run: tox -e old-dependencies build: strategy: fail-fast: false matrix: include: + - image: macos-14 + platform: macos-arm64 - image: macos-12 - platform: macos + platform: macos-x86_64 - image: windows-2019 platform: windows - image: ubuntu-20.04 # Oldest available version so we get oldest glibc possible. platform: linux runs-on: ${{ matrix.image }} - env: - CI_BUILD_KEY: ${{ secrets.CI_BUILD_KEY }} steps: - uses: actions/checkout@v4 with: persist-credentials: false fetch-depth: 0 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - - if: matrix.platform == 'windows' - uses: actions/cache@v3 - with: - path: release/installbuilder/setup - key: installbuilder - run: pip install .[dev] # pyinstaller 5.9 does not like pyproject.toml + editable installs. - # macOS x64. Due to GHA limitations, we are currently building the Apple Silicon app bundle outside of CI. - - if: matrix.platform == 'macos' && github.repository == 'mitmproxy/mitmproxy' + - if: startsWith(matrix.platform, 'macos') && github.repository == 'mitmproxy/mitmproxy' && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/')) id: keychain - uses: apple-actions/import-codesign-certs@5565bb656f60c98c8fc515f3444dd8db73545dc2 + uses: apple-actions/import-codesign-certs@63fff01cd422d4b7b855d40ca1e9d34d2de9427d with: keychain: ${{ runner.temp }}/temp p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - - if: matrix.platform == 'macos' && github.repository == 'mitmproxy/mitmproxy' + - if: startsWith(matrix.platform, 'macos') && github.repository == 'mitmproxy/mitmproxy' && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/')) run: | python -u release/build.py macos-app \ @@ -128,16 +137,43 @@ jobs: # Windows - if: matrix.platform == 'windows' run: python -u release/build.py standalone-binaries - - if: matrix.platform == 'windows' && github.repository == 'mitmproxy/mitmproxy' && - (github.ref == 'refs/heads/citest' || startsWith(github.ref, 'refs/tags/')) - run: python -u release/build.py --dirty installbuilder-installer msix-installer - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: - # artifacts must have different names, see https://github.com/actions/upload-artifact/issues/24 name: binaries.${{ matrix.platform }} - path: | - release/dist + path: release/dist + + build-wheel: + uses: mhils/workflows/.github/workflows/python-build.yml@v10 + with: + python-version-file: .github/python-version.txt + artifact: binaries.wheel + + build-windows-installer: + runs-on: windows-latest + if: github.repository == 'mitmproxy/mitmproxy' && ( + github.ref == 'refs/heads/main' || + github.ref == 'refs/heads/citest' || + startsWith(github.ref, 'refs/tags/') + ) + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version-file: .github/python-version.txt + + - run: pip install .[dev] # pyinstaller 5.9 does not like pyproject.toml + editable installs. + - run: python -u release/build.py installbuilder-installer msix-installer + env: + CI_BUILD_KEY: ${{ secrets.CI_BUILD_KEY }} + + - uses: actions/upload-artifact@v4 + with: + name: binaries.windows-installer + path: release/dist test-web-ui: runs-on: ubuntu-latest @@ -149,7 +185,7 @@ jobs: with: node-version-file: .github/node-version.txt - name: Cache Node.js modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm @@ -161,9 +197,26 @@ jobs: run: npm ci - working-directory: ./web run: npm test - - uses: mhils/better-codecov-action@main + - uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./web/coverage/coverage-final.json + + test-docker: + runs-on: ubuntu-latest + needs: build-wheel + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/download-artifact@v4 with: - arguments: '--file ./web/coverage/coverage-final.json' + name: binaries.wheel + path: release/docker + - name: Build container + run: docker build --tag localtesting release/docker + - name: Test container + run: docker run --rm -v $PWD/release:/release localtesting mitmdump -s /release/selftest.py docs: runs-on: ubuntu-latest @@ -171,7 +224,7 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: | @@ -180,7 +233,7 @@ jobs: sudo dpkg -i hugo*.deb - run: pip install -e .[dev] - run: ./docs/build.py - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: docs path: docs/public @@ -190,7 +243,7 @@ jobs: env: DOCS_ARCHIVE: true - if: startsWith(github.ref, 'refs/tags/') - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: docs-archive path: docs/public @@ -203,40 +256,86 @@ jobs: - mypy - individual-coverage - test - - build + - test-docker + - test-old-dependencies - test-web-ui + - build + - build-wheel + - build-windows-installer - docs - uses: mhils/workflows/.github/workflows/alls-green.yml@main + uses: mhils/workflows/.github/workflows/alls-green.yml@v10 with: jobs: ${{ toJSON(needs) }} + allowed-skips: build-windows-installer # Separate from everything else because slow. - build-and-deploy-docker: + deploy-docker: if: github.repository == 'mitmproxy/mitmproxy' && ( - github.ref == 'refs/heads/main' - || github.ref == 'refs/heads/citest' - || startsWith(github.ref, 'refs/tags/') + github.ref == 'refs/heads/main' || + github.ref == 'refs/heads/citest' || + startsWith(github.ref, 'refs/tags/') ) + permissions: + id-token: write + attestations: write + packages: write environment: deploy-docker needs: check runs-on: ubuntu-latest - env: - DOCKER_USERNAME: mitmbot - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} steps: - uses: actions/checkout@v4 with: persist-credentials: false - - uses: actions/setup-python@v4 + - uses: actions/download-artifact@v4 with: - python-version-file: .github/python-version.txt - - uses: actions/download-artifact@v3 + name: binaries.wheel + path: release/docker + - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + - uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v1.6.0 + + - name: Login to Docker Hub + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: - name: binaries.linux - path: release/dist - - uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 - - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v1.6.0 - - run: python release/build-and-deploy-docker.py + username: mitmbot + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Login to GitHub Container Registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker meta + id: meta + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 + env: + DOCKER_METADATA_ANNOTATIONS_LEVELS: index + with: + images: | + mitmproxy/mitmproxy + ghcr.io/mitmproxy/mitmproxy + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=dev,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=citest,enable=${{ github.ref == 'refs/heads/citest' }} + + - name: Build and push + id: push + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + with: + context: release/docker + platforms: linux/amd64,linux/arm64 + push: true + provenance: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + annotations: ${{ steps.meta.outputs.annotations }} + - uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/${{ github.repository }} + subject-digest: ${{ steps.push.outputs.digest }} deploy: # This action has access to our AWS keys, so we are extra careful here. @@ -245,6 +344,9 @@ jobs: environment: ${{ (github.ref == 'refs/heads/citest' || startsWith(github.ref, 'refs/tags/')) && 'deploy-release' || 'deploy-snapshot' }} needs: check runs-on: ubuntu-latest + permissions: + id-token: write + attestations: write env: # PyPI and MSFT keys are only available for the deploy-release environment # The AWS access key for snapshots is scoped to branches/* as well. @@ -264,7 +366,7 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: sudo apt-get update @@ -272,27 +374,27 @@ jobs: - if: startsWith(github.ref, 'refs/tags/') run: sudo apt-get install -y twine - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: docs path: docs/public - if: startsWith(github.ref, 'refs/tags/') - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: docs-archive path: docs/archive - - uses: actions/download-artifact@v3 - with: - name: binaries.windows - path: release/dist - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: - name: binaries.linux + pattern: binaries.* + merge-multiple: true path: release/dist - - uses: actions/download-artifact@v3 + - id: provenance + uses: actions/attest-build-provenance@v1 with: - name: binaries.macos - path: release/dist + subject-path: 'release/dist/*' + - run: | + REF=${{ github.ref_name }} + mv ${{ steps.provenance.outputs.bundle-path }} release/dist/mitmproxy-${REF#v}.sigstore - run: ls docs/public - run: ls release/dist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69db1f7eed..161d80e7b4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version-file: .github/node-version.txt - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: ./release/release.py ${{ inputs.version }} ${{ inputs.skip-branch-status-check }} diff --git a/.gitignore b/.gitignore index 2a6f5eb373..a5dfafcc27 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ MANIFEST **/tmp /venv* +/.venv* *.py[cdo] *.swp *.swo diff --git a/CHANGELOG.md b/CHANGELOG.md index 7db955d1f3..02b1a7f91f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,273 @@ # Release History - ## Unreleased: mitmproxy next -* Improved handling for `--allow-hosts`/`--ignore-hosts` options in WireGuard mode (#5930). + +## 02 October 2024: mitmproxy 11.0.0 + +- mitmproxy now supports transparent HTTP/3 proxying. + ([#7202](https://github.com/mitmproxy/mitmproxy/pull/7202), @errorxyz, @meitinger, @mhils) +- Add HTTP3 support in HTTPS reverse-proxy mode. + ([#7114](https://github.com/mitmproxy/mitmproxy/pull/7114), @errorxyz) +- mitmproxy now officially supports Python 3.13. + ([#6934](https://github.com/mitmproxy/mitmproxy/pull/6934), @mhils) +- Tighten HTTP detection heuristic to better support custom TCP-based protocols. + ([#7087](https://github.com/mitmproxy/mitmproxy/pull/7087)) +- Add `show_ignored_hosts` option to display ignored flows in the UI. + This option is implemented as a temporary workaround and will be removed in the future. + ([#6720](https://github.com/mitmproxy/mitmproxy/pull/6720), @NicolaiSoeborg) +- Fix slow tnetstring parsing in case of very large tnetstring. + ([#7121](https://github.com/mitmproxy/mitmproxy/pull/7121), @mik1904) +- Add `getaddrinfo`-based fallback for DNS resolution if we are unable to + determine the operating system's name servers. + ([#7122](https://github.com/mitmproxy/mitmproxy/pull/7122), @mhils) +- Improve the error message when users specify the `certs` option without a matching private key. + ([#7073](https://github.com/mitmproxy/mitmproxy/pull/7073), @mhils) +- Fix a bug where intermediate certificates would not be transmitted when using QUIC. + ([#7073](https://github.com/mitmproxy/mitmproxy/pull/7073), @mhils) +- Fix a bug where fragmented QUIC client hellos were not handled properly. + ([#7067](https://github.com/mitmproxy/mitmproxy/pull/7067), @errorxyz) +- Emit a warning when users configure a TLS version that is not supported by the + current OpenSSL build. + ([#7139](https://github.com/mitmproxy/mitmproxy/pull/7139), @mhils) +- Fix a bug where mitmproxy would crash when receiving `STOP_SENDING` QUIC frames. + ([#7119](https://github.com/mitmproxy/mitmproxy/pull/7119), @mhils) +- Fix error when unmarking all flows. + ([#7192](https://github.com/mitmproxy/mitmproxy/pull/7192), @bburky) +- Add addon to update the alt-svc header in reverse mode. + ([#7093](https://github.com/mitmproxy/mitmproxy/pull/7093), @errorxyz) +- Do not send unnecessary empty data frames when streaming HTTP/2. + ([#7196](https://github.com/mitmproxy/mitmproxy/pull/7196), @rubu) +- Fix a bug where mitmproxy would ignore Ctrl+C/SIGTERM on OpenBSD. + ([#7130](https://github.com/mitmproxy/mitmproxy/pull/7130), @catap) +- Fix of measurement unit in HAR import, duration is in milliseconds. + ([#7179](https://github.com/mitmproxy/mitmproxy/pull/7179), @dstd) +- `Connection.tls_version` now is `QUICv1` instead of `QUIC` for QUIC. + ([#7201](https://github.com/mitmproxy/mitmproxy/pull/7201), @mhils) +- Add support for full mTLS with client certs between client and mitmproxy. + ([#7175](https://github.com/mitmproxy/mitmproxy/pull/7175), @Kriechi) +- Update documentation adding a list of all possibile web_columns. + ([#7205](https://github.com/mitmproxy/mitmproxy/pull/7205), @lups2000, @Abhishek-Bohora) + +## 02 August 2024: mitmproxy 10.4.2 + +- Fix a crash on startup when mitmproxy is unable to determine the OS' DNS servers + ([#7066](https://github.com/mitmproxy/mitmproxy/pull/7066), @errorxyz) + +## 29 July 2024: mitmproxy 10.4.1 + +- Fix a bug where macOS local mode would not start up on macOS. + ([#7045](https://github.com/mitmproxy/mitmproxy/pull/7045), @mhils) +- Fix UDP error handling when we learn that the remote has disconnected. + ([#7045](https://github.com/mitmproxy/mitmproxy/pull/7045), @mhils) +- Container images are now published to both Docker Hub and GitHub Container Registry. + ([#7061](https://github.com/mitmproxy/mitmproxy/pull/7061), @mhils) + +## 25 July 2024: mitmproxy 10.4.0 + +* Add support for DNS over TCP. + ([#6935](https://github.com/mitmproxy/mitmproxy/pull/6935), @errorxyz) +* Add first MVP new Capture Tab in mitmweb + ([#6999](https://github.com/mitmproxy/mitmproxy/pull/6999), @lups2000) +* Add `HttpConnectedHook` and `HttpConnectErrorHook`. + ([#6930](https://github.com/mitmproxy/mitmproxy/pull/6930), @errorxyz) +* Fix non-linear growth in processing time for large HTTP bodies. + ([#6952](https://github.com/mitmproxy/mitmproxy/pull/6952), @jackfromeast) +* Fix a bug where connections would be incorrectly ignored with `allow_hosts`. + ([#7002](https://github.com/mitmproxy/mitmproxy/pull/7002), @JarLob, @mhils) +* Fix zstd decompression to read across frames. + ([#6921](https://github.com/mitmproxy/mitmproxy/pull/6921), @zendai) +* Handle certificates we cannot parse more gracefully. + ([#6994](https://github.com/mitmproxy/mitmproxy/pull/6994), @mhils) +* Parse compressed domain names in ResourceRecord data. + ([#6954](https://github.com/mitmproxy/mitmproxy/pull/6954), @errorxyz) +* Fix a bug where mitmweb's flow list would not stay at the bottom. + ([#7008](https://github.com/mitmproxy/mitmproxy/pull/7008), @mhils) +* Fix a bug where SSH connections would be incorrectly handled as HTTP. + ([#7041](https://github.com/mitmproxy/mitmproxy/pull/7041), @mhils) +* Skip UTF-8 byte-order marks (BOM) when loading HAR files. + ([#6897](https://github.com/mitmproxy/mitmproxy/pull/6897), @dstd) +* Allow `typing.Sequence[str]` to be an editable option. + ([#7001](https://github.com/mitmproxy/mitmproxy/pull/7001), @errorxyz) +* Add Host header to CONNECT requests. + ([#7021](https://github.com/mitmproxy/mitmproxy/pull/7021), @petsneakers) +* Support all query types in DNS mode. + ([#6975](https://github.com/mitmproxy/mitmproxy/pull/6975), @errorxyz) +* Fix a bug where mitmproxy would crash for pipelined HTTP flows. + ([#7031](https://github.com/mitmproxy/mitmproxy/pull/7031), @gdiepen, @mhils) +* Add an optional "index" column for mitmweb. + ([#7039](https://github.com/mitmproxy/mitmproxy/pull/7039), @mhils) + +## 12 June 2024: mitmproxy 10.3.1 + +* Release tags are now prefixed with `v` again. + ([#6810](https://github.com/mitmproxy/mitmproxy/pull/6810), @mhils) +* Fix a bug where mitmproxy would not exit when `-n` is passed. + ([#6819](https://github.com/mitmproxy/mitmproxy/pull/6819), @mhils) +* Set the `unbuffered` (stdout/stderr) flag for the `mitmdump` PyInstaller build. + ([#6821](https://github.com/mitmproxy/mitmproxy/pull/6821), @Prinzhorn) +* Fix a bug where client replay would not work with proxyauth. + ([#6866](https://github.com/mitmproxy/mitmproxy/pull/6866), @mhils) +* Fix slowdown when sending large amounts of data over HTTP/2. + ([#6875](https://github.com/mitmproxy/mitmproxy/pull/6875), @aib) +* Add an option to strip HTTPS records from DNS responses to block encrypted ClientHellos. + ([#6876](https://github.com/mitmproxy/mitmproxy/pull/6876), @errorxyz) +* Add an API to parse HTTPS records from DNS RDATA. + ([#6884](https://github.com/mitmproxy/mitmproxy/pull/6884), @errorxyz) +* Fix flow export in mitmweb for Safari + ([#6917](https://github.com/mitmproxy/mitmproxy/pull/6917), @mhils, @canyesilyurt) +* Releases now come with a Sigstore attestations file to demonstrate build provenance. + ([f05c050](https://github.com/mitmproxy/mitmproxy/commit/f05c050f615b9ab9963707944c893bc94e738525), @mhils) + +## 17 April 2024: mitmproxy 10.3.0 + +* Add support for editing non text files in a hex editor + ([#6768](https://github.com/mitmproxy/mitmproxy/pull/6768), @wnyyyy) +* Add `server_connect_error` hook that is triggered when connection establishment fails. + ([#6806](https://github.com/mitmproxy/mitmproxy/pull/6806), @haanhvu, @spacewasp, @mhils) +* Add section in mitmweb for rendering, adding and removing a comment + ([#6709](https://github.com/mitmproxy/mitmproxy/pull/6709), @lups2000) +* Fix multipart form content view being unusable. + ([#6653](https://github.com/mitmproxy/mitmproxy/pull/6653), @DaniElectra) +* Documentation Improvements on CA Certificate Generation + ([#5370](https://github.com/mitmproxy/mitmproxy/pull/5370), @zioalex) +* Make it possible to read flows from stdin with mitmweb. + ([#6732](https://github.com/mitmproxy/mitmproxy/pull/6732), @jaywor1) +* Update aioquic dependency to >= 1.0.0, < 2.0.0. + ([#6747](https://github.com/mitmproxy/mitmproxy/pull/6747), @jlaine) +* Fix a bug where async `client_connected` handlers would crash mitmproxy. + ([#6749](https://github.com/mitmproxy/mitmproxy/pull/6749), @mhils) +* Add button to close flow details panel + ([#6734](https://github.com/mitmproxy/mitmproxy/pull/6734), @lups2000) +* Ignore SIGPIPE signals when there is lots of traffic. + Socket errors are handled directly and do not require extra signals + that generate noise. + ([#6764](https://github.com/mitmproxy/mitmproxy/pull/6764), @changsin) +* Add primitive websocket interception and modification + ([#6766](https://github.com/mitmproxy/mitmproxy/pull/6766), @errorxyz) +* Add support for exporting websocket messages when using "raw" export. + ([#6767](https://github.com/mitmproxy/mitmproxy/pull/6767), @txrp0x9) +* The "save body" feature now also includes WebSocket messages. + ([#6767](https://github.com/mitmproxy/mitmproxy/pull/6767), @txrp0x9) +* Fix compatibility with older cryptography versions and silence a DeprecationWarning on Python <3.11. + ([#6790](https://github.com/mitmproxy/mitmproxy/pull/6790), @mhils) +* Fix a bug when proxying unicode domains. + ([#6796](https://github.com/mitmproxy/mitmproxy/pull/6796), @mhils) + + +## 07 March 2024: mitmproxy 10.2.4 + +* Fix a bug where errors during startup would not be displayed when running mitmproxy. + ([#6719](https://github.com/mitmproxy/mitmproxy/pull/6719), @mhils) +* Use newer cryptography APIs to avoid CryptographyDeprecationWarnings. + This bumps the minimum required version to cryptography 42.0. + ([#6718](https://github.com/mitmproxy/mitmproxy/pull/6718), @mhils) + + +## 06 March 2024: mitmproxy 10.2.3 + +* Fix a regression where `allow_hosts`/`ignore_hosts` would break with IPv6 connections. + ([#6614](https://github.com/mitmproxy/mitmproxy/pull/6614), @dqxpb) +* Fix bug where failed CONNECT request URLs are saved to HAR files incorrectly. + ([#6599](https://github.com/mitmproxy/mitmproxy/pull/6599), @basedBaba) +* Add an arm64 variant for the precompiled macOS app. + ([#6633](https://github.com/mitmproxy/mitmproxy/pull/6633), @mhils) +* Fix duplicate answers being returned in DNS queries. + ([#6648](https://github.com/mitmproxymitmproxy/pull/6648), @sujaldev) +* Fix bug where wireguard config is generated with incorrect endpoint when two or more NICs are active. + ([#6659](https://github.com/mitmproxy/mitmproxy/pull/6659), @basedBaba) +* Fix a regression when leaf cert creation would fail with intermediate CAs in `ca_file`. + ([#6666](https://github.com/mitmproxy/mitmproxy/pull/6666), @manselmi) +* Add `content_view_lines_cutoff` option to mitmdump + ([#6692](https://github.com/mitmproxy/mitmproxy/pull/6692), @errorxyz) +* Allow runtime modifications of HTTP flow filters for server replays + ([#6695](https://github.com/mitmproxy/mitmproxy/pull/6695), @errorxyz) +* Fix bug view options menu in case of overflow + ([#6697](https://github.com/mitmproxy/mitmproxy/pull/6697), @lups2000) +* Allow --allow-hosts and --ignore-hosts to work together + ([#6711](https://github.com/mitmproxy/mitmproxy/pull/6711), @dstd) + + +## 21 January 2024: mitmproxy 10.2.2 + +* Fix a regression where clientplayback would break due to eager task execution. + ([#6605](https://github.com/mitmproxy/mitmproxy/pull/6605), @mhils) +* Fix a regression where WebSocket connections would break due to eager task execution. + ([#6609](https://github.com/mitmproxy/mitmproxy/pull/6609), @mhils) +* Fix bug where insecure HTTP requests are saved incorrectly when exporting to HAR files. + ([#6578](https://github.com/mitmproxy/mitmproxy/pull/6578), @DaniElectra) +* `allow_hosts`/`ignore_hosts` option now matches against the full `host:port` string. + ([#6594](https://github.com/mitmproxy/mitmproxy/pull/6594), @LouisAsanaka) + + +## 06 January 2024: mitmproxy 10.2.1 + +* Fix a regression introduced in mitmproxy 10.2.0: WireGuard servers + now bind to all interfaces again. + ([#6587](https://github.com/mitmproxy/mitmproxy/pull/6587), @mhils) +* Remove stale reference to `ctx.log` in addon documentation. + ([#6552](https://github.com/mitmproxy/mitmproxy/pull/6552), @brojonat) +* Fix a bug where a traceback is shown during shutdown. + ([#6581](https://github.com/mitmproxy/mitmproxy/pull/6581), @mhils) + + +## 04 January 2024: mitmproxy 10.2.0 + +* *Local Redirect Mode* is now officially available on + [macOS](https://mitmproxy.org/posts/local-redirect/macos/) + and [Windows](https://mitmproxy.org/posts/local-redirect/windows/). + See the linked blog posts for details. (@emanuele-em, @mhils) +* UDP streams are now backed by a new implementation in `mitmproxy_rs`. + This represents a major API change as UDP traffic is now exposed as streams + instead of a callback for each packet. (@mhils) +* Fix a regression from mitmproxy 10.1.6 where `ignore_hosts` would terminate requests + instead of forwarding them. + ([#6559](https://github.com/mitmproxy/mitmproxy/pull/6559), @mhils) +* `ignore_hosts` now waits for the entire HTTP headers if it suspects the connection to be HTTP. + ([#6559](https://github.com/mitmproxy/mitmproxy/pull/6559), @mhils) + + +## 14 December 2023: mitmproxy 10.1.6 + +* Fix compatibility with Windows Schannel clients, which previously got + confused by CA and leaf certificate sharing the same Subject Key Identifier. + ([#6549](https://github.com/mitmproxy/mitmproxy/pull/6549), @driuba and @mhils) +* Change keybinding for exporting flow from "e" to "x" to avoid conflict with "edit" keybinding. + ([#6225](https://github.com/mitmproxy/mitmproxy/issues/6225), @Llama1412) +* Fix bug where response flows from HAR files had incorrect `content-length` headers + ([#6548](https://github.com/mitmproxy/mitmproxy/pull/6548), @zanieb) +* Improved handling for `allow_hosts`/`ignore_hosts` options in WireGuard mode (#5930). ([#6513](https://github.com/mitmproxy/mitmproxy/pull/6513), @dsphper) -* DNS resolution is now exempted from `--ignore-hosts` in WireGuard Mode. +* Fix a bug where TCP connections were not closed properly. + ([#6543](https://github.com/mitmproxy/mitmproxy/pull/6543), @mhils) +* DNS resolution is now exempted from `ignore_hosts` in WireGuard Mode. ([#6513](https://github.com/mitmproxy/mitmproxy/pull/6513), @dsphper) +* Fix case sensitivity of URL added to blocklist + ([#6493](https://github.com/mitmproxy/mitmproxy/pull/6493), @emanuele-em) * Fix a bug where logging was stopped prematurely during shutdown. ([#6541](https://github.com/mitmproxy/mitmproxy/pull/6541), @mhils) -* For plaintext traffic, `--ignore-hosts` now also takes HTTP/1 host headers into account. +* For plaintext traffic, `ignore_hosts` now also takes HTTP/1 host headers into account. ([#6513](https://github.com/mitmproxy/mitmproxy/pull/6513), @dsphper) * Fix empty cookie attributes being set to `Key=` instead of `Key` ([#5084](https://github.com/mitmproxy/mitmproxy/pull/5084), @Speedlulu) * Scripts with relative paths are now loaded relative to the config file and not where the command is ran ([#4860](https://github.com/mitmproxy/mitmproxy/pull/4860), @Speedlulu) +* Fix `mitmweb` splitter becoming drag and drop. + ([#6492](https://github.com/mitmproxy/mitmproxy/pull/6492), @xBZZZZ) * Enhance documentation and add alert log messages when stream_large_bodies and modify_body are set ([#6514](https://github.com/mitmproxy/mitmproxy/pull/6514), @rosydawn6) +### Breaking Changes + +* Subject Alternative Names are now represented as `cryptography.x509.GeneralNames` instead of `list[str]` + across the codebase. This fixes a regression introduced in mitmproxy 10.1.1 related to punycode domain encoding. + ([#6537](https://github.com/mitmproxy/mitmproxy/pull/6537), @mhils) + ## 14 November 2023: mitmproxy 10.1.5 @@ -98,7 +344,7 @@ details. - On Windows, `mitmproxy-rs` now depends on `mitmproxy-windows`. We only provide binary wheels for this package to simplify our deployment process, see CI for how to build from source. - + ([#6303](https://github.com/mitmproxy/mitmproxy/issues/6303), @mhils) * Increase maximum dump file size accepted by mitmweb ([#6373](https://github.com/mitmproxy/mitmproxy/pull/6373), @t-wy) @@ -108,7 +354,7 @@ * Add experimental support for HTTP/3 and QUIC. ([#5435](https://github.com/mitmproxy/mitmproxy/issues/5435), @meitinger) -* ASGI/WSGI apps can now listen on all ports for a specific hostname. +* ASGI/WSGI apps can now listen on all ports for a specific hostname. This makes it simpler to accept both HTTP and HTTPS. ([#5725](https://github.com/mitmproxy/mitmproxy/pull/5725), @mhils) * Add `replay.server.add` command for adding flows to server replay buffer @@ -180,7 +426,7 @@ ([#5414](https://github.com/mitmproxy/mitmproxy/pull/5414), @meitinger) * Add WireGuard mode to enable transparent proxying via WireGuard. ([#5562](https://github.com/mitmproxy/mitmproxy/pull/5562), @decathorpe, @mhils) -* Add DTLS support. +* Add DTLS support. ([#5397](https://github.com/mitmproxy/mitmproxy/pull/5397), @kckeiks). * Add a quick help bar to mitmproxy. ([#5381](https://github.com/mitmproxy/mitmproxy/pull/5381/), [#5652](https://github.com/mitmproxy/mitmproxy/pull/5652), @kckeiks, @mhils). @@ -193,7 +439,7 @@ * Deprecate `mitmproxy.ctx.log` in favor of Python's builtin `logging` module. See [the docs](https://docs.mitmproxy.org/dev/addons-api-changelog/) for details and upgrade instructions. ([#5590](https://github.com/mitmproxy/mitmproxy/pull/5590), @mhils) - + ### Breaking Changes * The `mode` option is now a list of server specs instead of a single spec. @@ -210,7 +456,7 @@ ([#5623](https://github.com/mitmproxy/mitmproxy/issues/5623), @SapiensAnatis) * Add MQTT content view. ([#5588](https://github.com/mitmproxy/mitmproxy/pull/5588), @nikitastupin, @abbbe) -* Setting `connection_strategy` to `lazy` now also disables early +* Setting `connection_strategy` to `lazy` now also disables early upstream connections to fetch TLS certificate details. ([#5487](https://github.com/mitmproxy/mitmproxy/pull/5487), @mhils) * Fix order of event hooks on startup. @@ -280,7 +526,7 @@ ([#4469](https://github.com/mitmproxy/mitmproxy/issues/4469), @mhils) * Add flatpak support to the browser addon ([#5200](https://github.com/mitmproxy/mitmproxy/issues/5200), @pauloromeira) -* Add example addon to dump contents to files based on a filter expression +* Add example addon to dump contents to files based on a filter expression ([#5190](https://github.com/mitmproxy/mitmproxy/issues/5190), @redraw) * Fix a bug where the wrong SNI is sent to an upstream HTTPS proxy ([#5109](https://github.com/mitmproxy/mitmproxy/issues/5109), @mhils) @@ -290,14 +536,14 @@ ([#5217](https://github.com/mitmproxy/mitmproxy/issues/5217), @randomstuff) * Improve cut addon to better handle binary contents ([#3965](https://github.com/mitmproxy/mitmproxy/issues/3965), @mhils) -* Fix text truncation for full-width characters +* Fix text truncation for full-width characters ([#4278](https://github.com/mitmproxy/mitmproxy/issues/4278), @kjy00302) * Fix mitmweb export copy failed in non-secure domain. ([#5264](https://github.com/mitmproxy/mitmproxy/issues/5264), @Pactortester) * Add example script for manipulating cookies. ([#5278](https://github.com/mitmproxy/mitmproxy/issues/5278), @WillahScott) -* When opening an external viewer for message contents, mailcap files are not considered anymore. - This preempts the upcoming deprecation of Python's `mailcap` module. +* When opening an external viewer for message contents, mailcap files are not considered anymore. + This preempts the upcoming deprecation of Python's `mailcap` module. ([#5297](https://github.com/mitmproxy/mitmproxy/issues/5297), @KORraNpl) * Fix hostname encoding for IDNA domains in upstream mode. ([#5316](https://github.com/mitmproxy/mitmproxy/issues/5316), @nneonneo) @@ -358,7 +604,7 @@ * Add ability to specify custom ports with LDAP authentication (#5068, @demonoidvk) * Add support for rotating saved streams every hour or day (@EndUser509) * Console Improvements on Windows (@mhils) -* Fix processing of `--set` options (#5067, @marwinxxii) +* Fix processing of `--set` options (#5067, @marwinxxii) * Lowercase user-added header names and emit a log message to notify the user when using HTTP/2 (#4746, @mhils) * Exit early if there are errors on startup (#4544, @mhils) * Fixed encoding guessing: only search for meta tags in HTML bodies (##4566, @Prinzhorn) diff --git a/README.md b/README.md index f23dbd7c9e..5563ec46bf 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,3 @@ use GitHub Discussions! As an open source project, mitmproxy welcomes contributions of all forms. [![Dev Guide](https://shields.mitmproxy.org/badge/dev_docs-CONTRIBUTING.md-blue)](./CONTRIBUTING.md) - -Also, please feel free to join our developer Slack! However, please note that the primary purpose of our Slack is direct communication between maintainers and contributors. **If you have questions where the answer might be valuable to others, please use [GitHub Discussions](https://github.com/mitmproxy/mitmproxy/discussions) and not Slack.** - -[![Slack Developer Chat](https://shields.mitmproxy.org/badge/slack-mitmproxy-E01563.svg)](http://slack.mitmproxy.org/) diff --git a/docs/scripts/api-events.py b/docs/scripts/api-events.py index be3f1e0b04..95bd7f111a 100644 --- a/docs/scripts/api-events.py +++ b/docs/scripts/api-events.py @@ -97,6 +97,7 @@ def category(name: str, desc: str, hooks: list[type[hooks.Hook]]) -> None: server_hooks.ServerConnectHook, server_hooks.ServerConnectedHook, server_hooks.ServerDisconnectedHook, + server_hooks.ServerConnectErrorHook, ], ) @@ -111,6 +112,8 @@ def category(name: str, desc: str, hooks: list[type[hooks.Hook]]) -> None: http.HttpErrorHook, http.HttpConnectHook, http.HttpConnectUpstreamHook, + http.HttpConnectedHook, + http.HttpConnectErrorHook, ], ) diff --git a/docs/src/content/addons-overview.md b/docs/src/content/addons-overview.md index a4f48efed0..e8bdba7b60 100644 --- a/docs/src/content/addons-overview.md +++ b/docs/src/content/addons-overview.md @@ -25,9 +25,9 @@ them to keys in the interactive tools. {{< example src="examples/addons/anatomy.py" lang="py" >}} Above is a simple addon that keeps track of the number of flows (or more -specifically HTTP requests) we've seen. Every time it sees a new flow, it uses -mitmproxy's internal logging mechanism to announce its tally. The output can be -found in the event log in the interactive tools, or on the console in mitmdump. +specifically HTTP requests) we've seen. Every time it sees a new flow, it +increments and logs its tally. The output can be found in the event log in the +interactive tools, or on the console in mitmdump. Take it for a spin and make sure that it does what it's supposed to, by loading it into your mitmproxy tool of choice. We'll use mitmdump in these examples, @@ -45,11 +45,6 @@ Here are a few things to note about the code above: - The `request` method is an example of an *event*. Addons simply implement a method for each event they want to handle. Each event and its signature are documented in the [API documentation]({{< relref "addons-api" >}}). -- Finally, the `ctx` module is a holdall module that exposes a set of standard - objects that are commonly used in addons. We could pass a `ctx` object as the - first parameter to every event, but we've found it neater to just expose it as - an importable global. In this case, we're using the `ctx.log` object to do our - logging. # Abbreviated Scripting Syntax diff --git a/docs/src/content/concepts-certificates.md b/docs/src/content/concepts-certificates.md index e65b704aa5..5759e614ef 100644 --- a/docs/src/content/concepts-certificates.md +++ b/docs/src/content/concepts-certificates.md @@ -1,8 +1,8 @@ --- title: "Certificates" menu: - concepts: - weight: 3 + concepts: + weight: 3 --- # About Certificates @@ -45,11 +45,9 @@ For security reasons, the mitmproxy CA is generated uniquely on the first start is not shared between mitmproxy installations on different devices. This makes sure that other mitmproxy users cannot intercept your traffic. - - ### Installing the mitmproxy CA certificate manually -Sometimes using the [quick install app](#quick-setup) is not an option and you need to install the CA manually. +Sometimes using the [quick install app](#quick-setup) is not an option and you need to install the CA manually. Below is a list of pointers to manual certificate installation documentation for some common platforms. The mitmproxy CA cert is located in `~/.mitmproxy` after it has been generated at the first start of mitmproxy. @@ -83,18 +81,17 @@ documentation for some common platforms. The mitmproxy CA cert is located in When mitmproxy receives a request to establish TLS (in the form of a ClientHello message), it puts the client on hold and first makes a connection to the upstream server to "sniff" the contents of its TLS certificate. -The information gained -- Common Name, Organization, Subject Alternative Names -- is then used to generate a new +The information gained -- Common Name, Organization, Subject Alternative Names -- is then used to generate a new interception certificate on-the-fly, signed by the mitmproxy CA. Mitmproxy then returns to the client and continues the handshake with the newly-forged certificate. Upstream cert sniffing is on by default, and can optionally be disabled by turning the `upstream_cert` option off. - ### Certificate Pinning Some applications employ [Certificate Pinning](https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning) to prevent -man-in-the-middle attacks. This means that **mitmproxy's** +man-in-the-middle attacks. This means that **mitmproxy's** certificates will not be accepted by these applications without modifying them. If the contents of these connections are not important, it is recommended to use the [ignore_hosts]({{< relref "howto-ignoredomains">}}) feature to prevent @@ -180,9 +177,9 @@ The `mitmproxy-ca.pem` certificate file has to look roughly like this: -----END CERTIFICATE----- -When looking at the certificate with +When looking at the certificate with `openssl x509 -noout -text -in ~/.mitmproxy/mitmproxy-ca.pem` -it should have at least the following X509v3 extensions so mitmproxy can +it should have at least the following X509v3 extensions so mitmproxy can use it to generate certificates: X509v3 extensions: @@ -191,8 +188,33 @@ use it to generate certificates: X509v3 Basic Constraints: critical CA:TRUE +For example, when using OpenSSL, you can create a CA authority as follows: + +```shell +openssl req -x509 -new -nodes -key ca.key -sha256 -out ca.crt -addext keyUsage=critical,keyCertSign +cat ca.key ca.crt > mitmproxy-ca.pem +``` + +## Mutual TLS (mTLS) and client certificates + +TLS is typically used in a way where the client verifies the server's identity +using the server's certificate during the handshake, but the server does not +verify the client's identity using the TLS protocol. Instead, the client +transmits cookies or other access tokens over the established secure channel to +authenticate itself. + +Mutual TLS (mTLS) is a mode where the server verifies the client's identity +not using cookies or access tokens, but using a certificate presented by the +client during the TLS handshake. With mTLS, both client and server use a +certificate to authenticate each other. + +If a server wants to verify the clients identity using mTLS, it sends an +additional `CertificateRequest` message to the client during the handshake. The +client then provides its certificate and proves ownership of the private key +with a matching signature. This part works just like server authentication, only +the other way around. -## Using a client side certificate +### mTLS between mitmproxy and upstream server You can use a client certificate by passing the `--set client_certs=DIRECTORY|FILE` option to mitmproxy. Using a directory allows certs to be selected based on @@ -200,9 +222,30 @@ hostname, while using a filename allows a single specific certificate to be used for all TLS connections. Certificate files must be in the PEM format and should contain both the unencrypted private key and the certificate. -### Multiple client certificates - You can specify a directory to `--set client_certs=DIRECTORY`, in which case the matching certificate is looked up by filename. So, if you visit example.org, mitmproxy looks for a file named `example.org.pem` in the specified directory and uses this as the client cert. + +### mTLS between client and mitmproxy + +By default, mitmproxy does not send the `CertificateRequest` TLS handshake +message to connecting clients. This is because it trips up some clients that do +not expect a certificate request (most famously old Android versions). However, +there are other clients -- in particular in the MQTT / IoT environment -- that +do expect a certificate request and will otherwise fail the TLS handshake. + +To instruct mitmproxy to request a client certificate from the connecting +client, you can pass the `--set request_client_cert=True` option. This will +generate a `CertificateRequest` TLS handshake message and (if successful) +establish an mTLS connection. This option only requests a certificate from the +client, it does not validate the presented identity in any way. For the purposes +of testing and developing client and server software, this is typically not an +issue. If you operate mitmproxy in an environment where untrusted clients might +connect, you need to safeguard against them. + +The `request_client_cert` option is typically paired with `client_certs` like so: + +```bash +mitmproxy --set request_client_cert=True --set client_certs=client-cert.pem +``` diff --git a/docs/src/content/concepts-filters.md b/docs/src/content/concepts-filters.md index 4f75cb7d03..1c198bca72 100644 --- a/docs/src/content/concepts-filters.md +++ b/docs/src/content/concepts-filters.md @@ -50,4 +50,4 @@ Anything but requests with a text/html content type: Replace entire GET string in a request (quotes required to make it work): - ":~q ~m GET:.*:/replacement.html" + ":~q ~m GET:.*:/replacement.html" diff --git a/docs/src/content/howto-ignoredomains.md b/docs/src/content/howto-ignoredomains.md index bcdff4f072..a5954717e5 100644 --- a/docs/src/content/howto-ignoredomains.md +++ b/docs/src/content/howto-ignoredomains.md @@ -15,9 +15,7 @@ mitmproxy's interception mechanism: and mitmproxy's interception leads to errors. For example, the Twitter app, Windows Update or the Apple App Store fail to work if mitmproxy is active. - **Convenience:** You really don't care about some parts of the traffic and - just want them to go away. Note that mitmproxy's "Limit" option is often the - better alternative here, as it is not affected by the limitations listed - below. + just want them to go away. Note that mitmproxy's [view_filter]({{< relref "concepts-options/#view_filter" >}}) option is often the better alternative here, as it is not affected by the limitations listed below. If you want to peek into (SSL-protected) non-HTTP connections, check out the **tcp_proxy** feature. If you want to ignore traffic from mitmproxy's processing diff --git a/docs/src/content/overview-getting-started.md b/docs/src/content/overview-getting-started.md index 7bcfd63598..944bb5f295 100644 --- a/docs/src/content/overview-getting-started.md +++ b/docs/src/content/overview-getting-started.md @@ -49,4 +49,3 @@ new flow and you can inspect it. * [**GitHub**](https://github.com/mitmproxy/mitmproxy): If you want to ask usage questions, contribute to mitmproxy, or submit a bug report, please use GitHub. -* [**Slack**](https://mitmproxy.slack.com): For ephemeral development questions/coordination, please use our Slack channel. diff --git a/docs/src/content/overview-installation.md b/docs/src/content/overview-installation.md index 8f7e86d5e8..db6f952969 100644 --- a/docs/src/content/overview-installation.md +++ b/docs/src/content/overview-installation.md @@ -21,6 +21,8 @@ brew install mitmproxy Alternatively, you can download standalone binaries on [mitmproxy.org](https://mitmproxy.org/). +NOTE: For Apple Silicon, Rosetta is required. + ## Linux The recommended way to install mitmproxy on Linux is to download the diff --git a/examples/addons/anatomy.py b/examples/addons/anatomy.py index 011ccd0f1f..a03404a91e 100644 --- a/examples/addons/anatomy.py +++ b/examples/addons/anatomy.py @@ -3,6 +3,7 @@ Run as follows: mitmproxy -s anatomy.py """ + import logging diff --git a/examples/addons/commands-flows.py b/examples/addons/commands-flows.py index 9cc196ca9b..fbe0bebeaa 100644 --- a/examples/addons/commands-flows.py +++ b/examples/addons/commands-flows.py @@ -1,4 +1,5 @@ """Handle flows as command arguments.""" + import logging from collections.abc import Sequence diff --git a/examples/addons/commands-paths.py b/examples/addons/commands-paths.py index e80ace5cb8..908d564808 100644 --- a/examples/addons/commands-paths.py +++ b/examples/addons/commands-paths.py @@ -1,4 +1,5 @@ """Handle file paths as command arguments.""" + import logging from collections.abc import Sequence diff --git a/examples/addons/commands-simple.py b/examples/addons/commands-simple.py index 86750a4b92..4edef09e60 100644 --- a/examples/addons/commands-simple.py +++ b/examples/addons/commands-simple.py @@ -1,4 +1,5 @@ """Add a custom command to mitmproxy's command prompt.""" + import logging from mitmproxy import command diff --git a/examples/addons/contentview-custom-grpc.py b/examples/addons/contentview-custom-grpc.py index 74ffd14b46..5229d189ec 100644 --- a/examples/addons/contentview-custom-grpc.py +++ b/examples/addons/contentview-custom-grpc.py @@ -3,6 +3,7 @@ protobuf messages based on a user defined rule set. """ + from mitmproxy import contentviews from mitmproxy.addonmanager import Loader from mitmproxy.contentviews.grpc import ProtoParser diff --git a/examples/addons/contentview.py b/examples/addons/contentview.py index 03d2a87a79..7d34874200 100644 --- a/examples/addons/contentview.py +++ b/examples/addons/contentview.py @@ -5,6 +5,7 @@ which is used to pretty-print HTTP bodies for example. The content view API is explained in the mitmproxy.contentviews module. """ + from mitmproxy import contentviews from mitmproxy import flow from mitmproxy import http diff --git a/examples/addons/duplicate-modify-replay.py b/examples/addons/duplicate-modify-replay.py index f11eb7c582..82f4ee4088 100644 --- a/examples/addons/duplicate-modify-replay.py +++ b/examples/addons/duplicate-modify-replay.py @@ -1,4 +1,5 @@ """Take incoming HTTP requests and replay them with modified parameters.""" + from mitmproxy import ctx diff --git a/examples/addons/filter-flows.py b/examples/addons/filter-flows.py index fe499228f9..43d8737492 100644 --- a/examples/addons/filter-flows.py +++ b/examples/addons/filter-flows.py @@ -1,6 +1,7 @@ """ Use mitmproxy's filter pattern in scripts. """ + from __future__ import annotations import logging diff --git a/examples/addons/http-modify-form.py b/examples/addons/http-modify-form.py index d3c73a72a1..7586adba71 100644 --- a/examples/addons/http-modify-form.py +++ b/examples/addons/http-modify-form.py @@ -1,4 +1,5 @@ """Modify an HTTP form submission.""" + from mitmproxy import http diff --git a/examples/addons/http-modify-query-string.py b/examples/addons/http-modify-query-string.py index 0139769d17..6908b72ce1 100644 --- a/examples/addons/http-modify-query-string.py +++ b/examples/addons/http-modify-query-string.py @@ -1,4 +1,5 @@ """Modify HTTP query parameters.""" + from mitmproxy import http diff --git a/examples/addons/http-redirect-requests.py b/examples/addons/http-redirect-requests.py index c5908aa49f..48390d5ad8 100644 --- a/examples/addons/http-redirect-requests.py +++ b/examples/addons/http-redirect-requests.py @@ -1,4 +1,5 @@ """Redirect HTTP requests to another server.""" + from mitmproxy import http diff --git a/examples/addons/http-reply-from-proxy.py b/examples/addons/http-reply-from-proxy.py index e6470a3da4..485fb499b8 100644 --- a/examples/addons/http-reply-from-proxy.py +++ b/examples/addons/http-reply-from-proxy.py @@ -1,4 +1,5 @@ """Send a reply from the proxy without sending the request to the remote server.""" + from mitmproxy import http diff --git a/examples/addons/http-stream-modify.py b/examples/addons/http-stream-modify.py index 9c59a338ed..11c26e4af2 100644 --- a/examples/addons/http-stream-modify.py +++ b/examples/addons/http-stream-modify.py @@ -7,6 +7,7 @@ - If you want to replace all occurrences of "foobar", make sure to catch the cases where one chunk ends with [...]foo" and the next starts with "bar[...]. """ + from collections.abc import Iterable diff --git a/examples/addons/http-trailers.py b/examples/addons/http-trailers.py index 2ac026cc0d..5822389a1b 100644 --- a/examples/addons/http-trailers.py +++ b/examples/addons/http-trailers.py @@ -6,6 +6,7 @@ headers by name, so the receiving endpoint can wait and read them after the body. """ + from mitmproxy import http from mitmproxy.http import Headers diff --git a/examples/addons/internet-in-mirror.py b/examples/addons/internet-in-mirror.py index 749eb1f322..e0abf88177 100644 --- a/examples/addons/internet-in-mirror.py +++ b/examples/addons/internet-in-mirror.py @@ -3,6 +3,7 @@ Useful if you are living down under. """ + from mitmproxy import http diff --git a/examples/addons/io-read-saved-flows.py b/examples/addons/io-read-saved-flows.py index 32da842d34..9fad123629 100644 --- a/examples/addons/io-read-saved-flows.py +++ b/examples/addons/io-read-saved-flows.py @@ -2,6 +2,7 @@ """ Read a mitmproxy dump file. """ + import pprint import sys diff --git a/examples/addons/io-write-flow-file.py b/examples/addons/io-write-flow-file.py index a348749de2..76fcbb46e5 100644 --- a/examples/addons/io-write-flow-file.py +++ b/examples/addons/io-write-flow-file.py @@ -7,8 +7,9 @@ flows should be saved and also allows you to rotate files or log to multiple files in parallel. """ + +import os import random -import sys from typing import BinaryIO from mitmproxy import http @@ -16,8 +17,11 @@ class Writer: - def __init__(self, path: str) -> None: - self.f: BinaryIO = open(path, "wb") + def __init__(self) -> None: + # We are using an environment variable to keep the example as simple as possible, + # consider implementing this as a mitmproxy option instead. + filename = os.getenv("MITMPROXY_OUTFILE", "out.mitm") + self.f: BinaryIO = open(filename, "wb") self.w = io.FlowWriter(self.f) def response(self, flow: http.HTTPFlow) -> None: @@ -28,4 +32,4 @@ def done(self): self.f.close() -addons = [Writer(sys.argv[1])] +addons = [Writer()] diff --git a/examples/addons/log-events.py b/examples/addons/log-events.py index 3ecfb8f982..08a6225be7 100644 --- a/examples/addons/log-events.py +++ b/examples/addons/log-events.py @@ -1,4 +1,5 @@ """Post messages to mitmproxy's event log.""" + import logging from mitmproxy.addonmanager import Loader diff --git a/examples/addons/nonblocking.py b/examples/addons/nonblocking.py index 8f7eab50d1..1be8cd7310 100644 --- a/examples/addons/nonblocking.py +++ b/examples/addons/nonblocking.py @@ -1,6 +1,7 @@ """ Make events hooks non-blocking using async or @concurrent. """ + import asyncio import logging import time diff --git a/examples/addons/options-configure.py b/examples/addons/options-configure.py index 81551b3dee..70efbf1e9c 100644 --- a/examples/addons/options-configure.py +++ b/examples/addons/options-configure.py @@ -1,4 +1,5 @@ """React to configuration changes.""" + from typing import Optional from mitmproxy import ctx diff --git a/examples/addons/options-simple.py b/examples/addons/options-simple.py index 6895a23be0..88ead1ee4e 100644 --- a/examples/addons/options-simple.py +++ b/examples/addons/options-simple.py @@ -5,6 +5,7 @@ mitmproxy -s options-simple.py --set addheader=true """ + from mitmproxy import ctx diff --git a/examples/addons/shutdown.py b/examples/addons/shutdown.py index 13629eeff9..cc8520037c 100644 --- a/examples/addons/shutdown.py +++ b/examples/addons/shutdown.py @@ -8,6 +8,7 @@ and then send a HTTP request to trigger the shutdown: curl --proxy localhost:8080 http://example.com/path """ + import logging from mitmproxy import ctx diff --git a/examples/addons/tcp-simple.py b/examples/addons/tcp-simple.py index ed90ba48f1..11a464522d 100644 --- a/examples/addons/tcp-simple.py +++ b/examples/addons/tcp-simple.py @@ -1,15 +1,16 @@ """ Process individual messages from a TCP connection. -This script replaces full occurences of "foo" with "bar" and prints various details for each message. +This script replaces full occurrences of "foo" with "bar" and prints various details for each message. Please note that TCP is stream-based and *not* message-based. mitmproxy splits stream contents into "messages" as they are received by socket.recv(). This is pretty arbitrary and should not be relied on. However, it is sometimes good enough as a quick hack. Example Invocation: - mitmdump --rawtcp --tcp-hosts ".*" -s examples/tcp-simple.py + mitmdump --tcp-hosts ".*" -s examples/tcp-simple.py """ + import logging from mitmproxy import tcp diff --git a/examples/addons/websocket-inject-message.py b/examples/addons/websocket-inject-message.py index 715f66e4d8..a2aa771ea7 100644 --- a/examples/addons/websocket-inject-message.py +++ b/examples/addons/websocket-inject-message.py @@ -3,6 +3,7 @@ This example shows how to inject a WebSocket message into a running connection. """ + import asyncio from mitmproxy import ctx diff --git a/examples/addons/websocket-simple.py b/examples/addons/websocket-simple.py index 8ced159106..9ec1e6b956 100644 --- a/examples/addons/websocket-simple.py +++ b/examples/addons/websocket-simple.py @@ -1,4 +1,5 @@ """Process individual messages from a WebSocket connection.""" + import logging import re diff --git a/examples/addons/wsgi-flask-app.py b/examples/addons/wsgi-flask-app.py index 7feab9d58b..01da441dea 100644 --- a/examples/addons/wsgi-flask-app.py +++ b/examples/addons/wsgi-flask-app.py @@ -5,6 +5,7 @@ instance, we're using the Flask framework (http://flask.pocoo.org/) to expose a single simplest-possible page. """ + from flask import Flask from mitmproxy.addons import asgiapp diff --git a/examples/contrib/all_markers.py b/examples/contrib/all_markers.py index 153818d03b..a2614259d9 100644 --- a/examples/contrib/all_markers.py +++ b/examples/contrib/all_markers.py @@ -10,4 +10,4 @@ def all_markers(): ctx.master.commands.call( "view.flows.create", "get", f"https://example.com/{marker}" ) - ctx.master.commands.call("flow.mark", [ctx.master.view.focus.flow], marker) + ctx.master.commands.call("flow.mark", [ctx.master.view[-1]], marker) diff --git a/examples/contrib/block_dns_over_https.py b/examples/contrib/block_dns_over_https.py index 2933ce6ce4..86b172cc37 100644 --- a/examples/contrib/block_dns_over_https.py +++ b/examples/contrib/block_dns_over_https.py @@ -4,6 +4,7 @@ It loads a blocklist of IPs and hostnames that are known to serve DNS over HTTPS requests. It also uses headers, query params, and paths to detect DoH (and block it) """ + import logging # known DoH providers' hostnames and IP addresses to block diff --git a/examples/contrib/change_upstream_proxy.py b/examples/contrib/change_upstream_proxy.py index 0a0d540673..682f02e86f 100644 --- a/examples/contrib/change_upstream_proxy.py +++ b/examples/contrib/change_upstream_proxy.py @@ -31,4 +31,4 @@ def request(flow: http.HTTPFlow) -> None: # server_conn already refers to an existing connection (which cannot be modified), # so we need to replace it with a new server connection object. flow.server_conn = Server(address=flow.server_conn.address) - flow.server_conn.via = ServerSpec("http", address) + flow.server_conn.via = ServerSpec(("http", address)) diff --git a/examples/contrib/custom_next_layer.py b/examples/contrib/custom_next_layer.py index 31e0887fc6..ffc6f1bb99 100644 --- a/examples/contrib/custom_next_layer.py +++ b/examples/contrib/custom_next_layer.py @@ -8,6 +8,7 @@ - mitmdump -s custom_next_layer.py - curl -x localhost:8080 -k https://example.com """ + import logging from mitmproxy import ctx diff --git a/examples/contrib/dns_spoofing.py b/examples/contrib/dns_spoofing.py index 75c80e8eba..304b9a5084 100644 --- a/examples/contrib/dns_spoofing.py +++ b/examples/contrib/dns_spoofing.py @@ -23,6 +23,7 @@ (Setting up a single proxy instance and using iptables to redirect to it works as well) """ + import re # This regex extracts splits the host header into host and port. diff --git a/examples/contrib/http_manipulate_cookies.py b/examples/contrib/http_manipulate_cookies.py index 184b0e8166..953ffa33a9 100644 --- a/examples/contrib/http_manipulate_cookies.py +++ b/examples/contrib/http_manipulate_cookies.py @@ -14,6 +14,7 @@ https://stackoverflow.com/questions/55358072/cookie-manipulation-in-mitmproxy-requests-and-responses """ + import json from mitmproxy import http diff --git a/examples/contrib/httpdump.py b/examples/contrib/httpdump.py index 532ed1e5d5..420667f730 100644 --- a/examples/contrib/httpdump.py +++ b/examples/contrib/httpdump.py @@ -6,7 +6,7 @@ # - dumper_folder: content dump destination folder (default: ./httpdump) # - open_browser: open integrated browser with proxy configured at start (default: true) # -# remember to add your own mitmproxy authorative certs in your browser/os! +# remember to add your own mitmproxy authoritative certs in your browser/os! # certs docs: https://docs.mitmproxy.org/stable/concepts-certificates/ # filter expressions docs: https://docs.mitmproxy.org/stable/concepts-filters/ import logging diff --git a/examples/contrib/jsondump.py b/examples/contrib/jsondump.py index cfde9b75c1..c25f724900 100644 --- a/examples/contrib/jsondump.py +++ b/examples/contrib/jsondump.py @@ -30,6 +30,7 @@ dump_destination: "/user/rastley/output.log" EOF """ + import base64 import json import logging diff --git a/examples/contrib/save_streamed_data.py b/examples/contrib/save_streamed_data.py index 6407705964..7053b75aab 100644 --- a/examples/contrib/save_streamed_data.py +++ b/examples/contrib/save_streamed_data.py @@ -18,6 +18,7 @@ This addon is not compatible with addons that use the same mechanism to capture streamed data, http-stream-modify.py for instance. """ + import logging import os from datetime import datetime diff --git a/examples/contrib/sslstrip.py b/examples/contrib/sslstrip.py index 6b88c39565..76344aa9eb 100644 --- a/examples/contrib/sslstrip.py +++ b/examples/contrib/sslstrip.py @@ -2,6 +2,7 @@ This script implements an sslstrip-like attack based on mitmproxy. https://moxie.org/software/sslstrip/ """ + import re import urllib.parse diff --git a/examples/contrib/suppress_error_responses.py b/examples/contrib/suppress_error_responses.py index 5cb319ef65..df4e50626b 100644 --- a/examples/contrib/suppress_error_responses.py +++ b/examples/contrib/suppress_error_responses.py @@ -4,6 +4,7 @@ Without this script, if the web application under test crashes, mitmproxy will send 502 Bad Gateway responses. These responses are irritating the web application scanner since they obfuscate the actual problem. """ + from mitmproxy import http from mitmproxy.exceptions import HttpSyntaxException diff --git a/examples/contrib/test_jsondump.py b/examples/contrib/test_jsondump.py index abb85c2903..0000b272fc 100644 --- a/examples/contrib/test_jsondump.py +++ b/examples/contrib/test_jsondump.py @@ -42,7 +42,7 @@ def test_contentencode(self, tmpdir): with taddons.context() as tctx: a = tctx.script(example_dir.path("complex/jsondump.py")) path = str(tmpdir.join("jsondump.out")) - content = b"foo" + b"\xFF" * 10 + content = b"foo" + b"\xff" * 10 tctx.configure(a, dump_destination=path, dump_encodecontent=True) tctx.invoke(a, "response", self.flow(resp_content=content)) diff --git a/examples/contrib/tls_passthrough.py b/examples/contrib/tls_passthrough.py index d0237d7937..6f43430d39 100644 --- a/examples/contrib/tls_passthrough.py +++ b/examples/contrib/tls_passthrough.py @@ -14,6 +14,7 @@ 3. curl --proxy http://localhost:8080 https://example.com // works again, but mitmproxy does not intercept and we do *not* see the contents """ + import collections import logging import random diff --git a/examples/contrib/xss_scanner.py b/examples/contrib/xss_scanner.py index eab9510a07..7d25d06e31 100644 --- a/examples/contrib/xss_scanner.py +++ b/examples/contrib/xss_scanner.py @@ -34,6 +34,7 @@ Line: 1029zxcs'd"aoso[sb]po(pc)se;sl/bsl\eq=3847asd """ + import logging import re import socket diff --git a/mitmproxy/addons/__init__.py b/mitmproxy/addons/__init__.py index fd36bb0cdd..c09c922984 100644 --- a/mitmproxy/addons/__init__.py +++ b/mitmproxy/addons/__init__.py @@ -25,7 +25,9 @@ from mitmproxy.addons import serverplayback from mitmproxy.addons import stickyauth from mitmproxy.addons import stickycookie +from mitmproxy.addons import strip_dns_https_records from mitmproxy.addons import tlsconfig +from mitmproxy.addons import update_alt_svc from mitmproxy.addons import upstream_auth @@ -34,6 +36,7 @@ def default_addons(): core.Core(), browser.Browser(), block.Block(), + strip_dns_https_records.StripDnsHttpsRecords(), blocklist.BlockList(), anticache.AntiCache(), anticomp.AntiComp(), @@ -60,4 +63,5 @@ def default_addons(): savehar.SaveHar(), tlsconfig.TlsConfig(), upstream_auth.UpstreamAuth(), + update_alt_svc.UpdateAltSvc(), ] diff --git a/mitmproxy/addons/block.py b/mitmproxy/addons/block.py index 8f6e37c195..cdd68bf97e 100644 --- a/mitmproxy/addons/block.py +++ b/mitmproxy/addons/block.py @@ -2,6 +2,7 @@ import logging from mitmproxy import ctx +from mitmproxy.proxy import mode_specs class Block: @@ -31,7 +32,7 @@ def client_connected(self, client): if isinstance(address, ipaddress.IPv6Address): address = address.ipv4_mapped or address - if address.is_loopback: + if address.is_loopback or isinstance(client.proxy_mode, mode_specs.LocalMode): return if ctx.options.block_private and address.is_private: diff --git a/mitmproxy/addons/clientplayback.py b/mitmproxy/addons/clientplayback.py index 53b202505a..b956bc600c 100644 --- a/mitmproxy/addons/clientplayback.py +++ b/mitmproxy/addons/clientplayback.py @@ -48,9 +48,9 @@ def __init__(self, flow: http.HTTPFlow, context: Context): def _handle_event(self, event: events.Event) -> CommandGenerator[None]: if isinstance(event, events.Start): content = self.flow.request.raw_content - self.flow.request.timestamp_start = ( - self.flow.request.timestamp_end - ) = time.time() + self.flow.request.timestamp_start = self.flow.request.timestamp_end = ( + time.time() + ) yield layers.http.ReceiveHttp( layers.http.RequestHeaders( 1, @@ -110,7 +110,7 @@ def __init__(self, flow: http.HTTPFlow, options: Options) -> None: self.done = asyncio.Event() async def replay(self) -> None: - self.server_event(events.Start()) + await self.server_event(events.Start()) await self.done.wait() def log( @@ -156,14 +156,18 @@ def __init__(self): self.replay_tasks = set() def running(self): + self.options = ctx.options self.playback_task = asyncio_utils.create_task( self.playback(), name="client playback" ) - self.options = ctx.options - def done(self): + async def done(self): if self.playback_task: self.playback_task.cancel() + try: + await self.playback_task + except asyncio.CancelledError: + pass async def playback(self): while True: diff --git a/mitmproxy/addons/core.py b/mitmproxy/addons/core.py index 5cd3f79adb..3056543798 100644 --- a/mitmproxy/addons/core.py +++ b/mitmproxy/addons/core.py @@ -68,7 +68,7 @@ def mark(self, flows: Sequence[flow.Flow], marker: mitmproxy.types.Marker) -> No Mark flows. """ updated = [] - if marker not in emoji.emoji: + if not (marker == "" or marker in emoji.emoji): raise exceptions.CommandError(f"invalid marker value") for i in flows: diff --git a/mitmproxy/addons/cut.py b/mitmproxy/addons/cut.py index c15ac3f539..c8be911272 100644 --- a/mitmproxy/addons/cut.py +++ b/mitmproxy/addons/cut.py @@ -12,6 +12,7 @@ from mitmproxy import command from mitmproxy import exceptions from mitmproxy import flow +from mitmproxy import http from mitmproxy.log import ALERT logger = logging.getLogger(__name__) @@ -28,6 +29,16 @@ def is_addr(v): def extract(cut: str, f: flow.Flow) -> str | bytes: + # Hack for https://github.com/mitmproxy/mitmproxy/issues/6721: + # Make "save body" keybind work for WebSocket flows. + # Ideally the keybind would be smarter and this here can get removed. + if ( + isinstance(f, http.HTTPFlow) + and f.websocket + and cut in ("request.content", "response.content") + ): + return f.websocket._get_formatted_messages() + path = cut.split(".") current: Any = f for i, spec in enumerate(path): diff --git a/mitmproxy/addons/disable_h2c.py b/mitmproxy/addons/disable_h2c.py index 595ce2b3f0..ae9e3f94e6 100644 --- a/mitmproxy/addons/disable_h2c.py +++ b/mitmproxy/addons/disable_h2c.py @@ -2,7 +2,6 @@ class DisableH2C: - """ We currently only support HTTP/2 over a TLS connection. diff --git a/mitmproxy/addons/dns_resolver.py b/mitmproxy/addons/dns_resolver.py index 63718050eb..7001bf1ecc 100644 --- a/mitmproxy/addons/dns_resolver.py +++ b/mitmproxy/addons/dns_resolver.py @@ -1,146 +1,108 @@ import asyncio import ipaddress +import logging import socket +from collections.abc import Awaitable from collections.abc import Callable -from collections.abc import Iterable +from collections.abc import Sequence +from functools import cache +import mitmproxy_rs +from mitmproxy import ctx from mitmproxy import dns +from mitmproxy.flow import Error from mitmproxy.proxy import mode_specs -IP4_PTR_SUFFIX = ".in-addr.arpa" -IP6_PTR_SUFFIX = ".ip6.arpa" +logger = logging.getLogger(__name__) -class ResolveError(Exception): - """Exception thrown by different resolve methods.""" - - def __init__(self, response_code: int) -> None: - assert response_code != dns.response_codes.NOERROR - self.response_code = response_code - - -async def resolve_question_by_name( - question: dns.Question, - loop: asyncio.AbstractEventLoop, - family: socket.AddressFamily, - ip: Callable[[str], ipaddress.IPv4Address | ipaddress.IPv6Address], -) -> Iterable[dns.ResourceRecord]: - try: - addrinfos = await loop.getaddrinfo(host=question.name, port=0, family=family) - except socket.gaierror as e: - if e.errno == socket.EAI_NONAME: - raise ResolveError(dns.response_codes.NXDOMAIN) - else: - # NOTE might fail on Windows for IPv6 queries: - # https://stackoverflow.com/questions/66755681/getaddrinfo-c-on-windows-not-handling-ipv6-correctly-returning-error-code-1 - raise ResolveError(dns.response_codes.SERVFAIL) # pragma: no cover - return map( - lambda addrinfo: dns.ResourceRecord( - name=question.name, - type=question.type, - class_=question.class_, - ttl=dns.ResourceRecord.DEFAULT_TTL, - data=ip(addrinfo[4][0]).packed, - ), - addrinfos, - ) - - -async def resolve_question_by_addr( - question: dns.Question, - loop: asyncio.AbstractEventLoop, - suffix: str, - sockaddr: Callable[[list[str]], tuple[str, int] | tuple[str, int, int, int]], -) -> Iterable[dns.ResourceRecord]: - try: - addr = sockaddr(question.name[: -len(suffix)].split(".")[::-1]) - except ValueError: - raise ResolveError(dns.response_codes.FORMERR) - try: - name, _ = await loop.getnameinfo(addr, flags=socket.NI_NAMEREQD) - except socket.gaierror as e: - raise ResolveError( - dns.response_codes.NXDOMAIN - if e.errno == socket.EAI_NONAME - else dns.response_codes.SERVFAIL - ) - return [ - dns.ResourceRecord( - name=question.name, - type=question.type, - class_=question.class_, - ttl=dns.ResourceRecord.DEFAULT_TTL, - data=dns.domain_names.pack(name), +class DnsResolver: + def load(self, loader): + loader.add_option( + "dns_use_hosts_file", + bool, + True, + "Use the hosts file for DNS lookups in regular DNS mode/wireguard mode.", ) - ] - -async def resolve_question( - question: dns.Question, loop: asyncio.AbstractEventLoop -) -> Iterable[dns.ResourceRecord]: - """Resolve the question into resource record(s), throwing ResolveError if an error condition occurs.""" - - if question.class_ != dns.classes.IN: - raise ResolveError(dns.response_codes.NOTIMP) - if question.type == dns.types.A: - return await resolve_question_by_name( - question, loop, socket.AddressFamily.AF_INET, ipaddress.IPv4Address - ) - elif question.type == dns.types.AAAA: - return await resolve_question_by_name( - question, loop, socket.AddressFamily.AF_INET6, ipaddress.IPv6Address + loader.add_option( + "dns_name_servers", + Sequence[str], + [], + "Name servers to use for lookups. Default: operating system's name servers", ) - elif question.type == dns.types.PTR: - name_lower = question.name.lower() - if name_lower.endswith(IP4_PTR_SUFFIX): - return await resolve_question_by_addr( - question=question, - loop=loop, - suffix=IP4_PTR_SUFFIX, - sockaddr=lambda x: (str(ipaddress.IPv4Address(".".join(x))), 0), + + def configure(self, updated): + if "dns_use_hosts_file" in updated or "dns_name_servers" in updated: + self.resolver.cache_clear() + self.name_servers.cache_clear() + + @cache + def name_servers(self) -> list[str]: + """ + The Operating System name servers, + or `[]` if they cannot be determined. + """ + try: + return ( + ctx.options.dns_name_servers + or mitmproxy_rs.dns.get_system_dns_servers() ) - elif name_lower.endswith(IP6_PTR_SUFFIX): - return await resolve_question_by_addr( - question=question, - loop=loop, - suffix=IP6_PTR_SUFFIX, - sockaddr=lambda x: ( - str(ipaddress.IPv6Address(bytes.fromhex("".join(x)))), - 0, - 0, - 0, - ), + except RuntimeError as e: + logger.warning( + f"Failed to get system dns servers: {e}\n" + f"The dns_name_servers option needs to be set manually." ) - else: - raise ResolveError(dns.response_codes.FORMERR) - else: - raise ResolveError(dns.response_codes.NOTIMP) - - -async def resolve_message( - message: dns.Message, loop: asyncio.AbstractEventLoop -) -> dns.Message: - try: - if not message.query: - raise ResolveError( - dns.response_codes.REFUSED - ) # we cannot resolve an answer - if message.op_code != dns.op_codes.QUERY: - raise ResolveError( - dns.response_codes.NOTIMP - ) # inverse queries and others are not supported - rrs: list[dns.ResourceRecord] = [] - for question in message.questions: - rrs.extend(await resolve_question(question, loop)) - except ResolveError as e: - return message.fail(e.response_code) - else: - return message.succeed(rrs) - + return [] + + @cache + def resolver(self) -> mitmproxy_rs.dns.DnsResolver: + """ + Our mitmproxy_rs DNS resolver. + """ + ns = self.name_servers() + assert ns + return mitmproxy_rs.dns.DnsResolver( + name_servers=ns, + use_hosts_file=ctx.options.dns_use_hosts_file, + ) -class DnsResolver: async def dns_request(self, flow: dns.DNSFlow) -> None: - should_resolve = ( + if self._should_resolve(flow): + all_ip_lookups = ( + flow.request.query + and flow.request.op_code == dns.op_codes.QUERY + and flow.request.question + and flow.request.question.class_ == dns.classes.IN + and flow.request.question.type in (dns.types.A, dns.types.AAAA) + ) + name_servers = self.name_servers() + + if all_ip_lookups: + # For A/AAAA records, we try to use our own resolver + # (with a fallback to getaddrinfo) + if name_servers: + flow.response = await self.resolve( + flow.request, self._with_resolver + ) + elif ctx.options.dns_use_hosts_file: + # Fallback to getaddrinfo as hickory's resolver isn't as reliable + # as we would like it to be (https://github.com/mitmproxy/mitmproxy/issues/7064). + flow.response = await self.resolve( + flow.request, self._with_getaddrinfo + ) + else: + flow.error = Error("Cannot resolve, dns_name_servers unknown.") + elif name_servers: + # For other records, the best we can do is to forward the query + # to an upstream server. + flow.server_conn.address = (name_servers[0], 53) + else: + flow.error = Error("Cannot resolve, dns_name_servers unknown.") + + @staticmethod + def _should_resolve(flow: dns.DNSFlow) -> bool: + return ( ( isinstance(flow.client_conn.proxy_mode, mode_specs.DnsMode) or ( @@ -152,8 +114,54 @@ async def dns_request(self, flow: dns.DNSFlow) -> None: and not flow.response and not flow.error ) - if should_resolve: - # TODO: We need to handle overly long responses here. - flow.response = await resolve_message( - flow.request, asyncio.get_running_loop() - ) + + async def resolve( + self, + message: dns.Message, + resolve_func: Callable[[dns.Question], Awaitable[list[str]]], + ) -> dns.Message: + assert message.question + try: + ip_addrs = await resolve_func(message.question) + except socket.gaierror as e: + match e.args[0]: + case socket.EAI_NONAME: + return message.fail(dns.response_codes.NXDOMAIN) + case socket.EAI_NODATA: + ip_addrs = [] + case _: + return message.fail(dns.response_codes.SERVFAIL) + + return message.succeed( + [ + dns.ResourceRecord( + name=message.question.name, + type=message.question.type, + class_=message.question.class_, + ttl=dns.ResourceRecord.DEFAULT_TTL, + data=ipaddress.ip_address(ip).packed, + ) + for ip in ip_addrs + ] + ) + + async def _with_resolver(self, question: dns.Question) -> list[str]: + """Resolve an A/AAAA question using the mitmproxy_rs DNS resolver.""" + if question.type == dns.types.A: + return await self.resolver().lookup_ipv4(question.name) + else: + return await self.resolver().lookup_ipv6(question.name) + + async def _with_getaddrinfo(self, question: dns.Question) -> list[str]: + """Resolve an A/AAAA question using getaddrinfo.""" + if question.type == dns.types.A: + family = socket.AF_INET + else: + family = socket.AF_INET6 + addrinfos = await asyncio.get_running_loop().getaddrinfo( + host=question.name, + port=None, + family=family, + type=socket.SOCK_STREAM, + ) + return [addrinfo[4][0] for addrinfo in addrinfos] diff --git a/mitmproxy/addons/dumper.py b/mitmproxy/addons/dumper.py index b76c34832a..5964f0e7fa 100644 --- a/mitmproxy/addons/dumper.py +++ b/mitmproxy/addons/dumper.py @@ -18,6 +18,7 @@ from mitmproxy import http from mitmproxy.contrib import click as miniclick from mitmproxy.net.dns import response_codes +from mitmproxy.options import CONTENT_VIEW_LINES_CUTOFF from mitmproxy.tcp import TCPFlow from mitmproxy.tcp import TCPMessage from mitmproxy.udp import UDPFlow @@ -54,12 +55,12 @@ def load(self, loader): "flow_detail", int, 1, - """ + f""" The display detail level for flows in mitmdump: 0 (quiet) to 4 (very verbose). 0: no output 1: shortened request URL with response status code 2: full request URL with response status code and HTTP headers - 3: 2 + truncated response content, content of WebSocket and TCP messages + 3: 2 + truncated response content, content of WebSocket and TCP messages (content_view_lines_cutoff: {CONTENT_VIEW_LINES_CUTOFF}) 4: 3 + nothing is truncated """, ) @@ -125,7 +126,9 @@ def _echo_message( logging.debug(error) if ctx.options.flow_detail == 3: - lines_to_echo = itertools.islice(lines, 70) + lines_to_echo = itertools.islice( + lines, ctx.options.content_view_lines_cutoff + ) else: lines_to_echo = lines @@ -344,7 +347,7 @@ def _proto_message(self, f: TCPFlow | UDPFlow) -> None: if self.match(f): message = f.messages[-1] direction = "->" if message.from_client else "<-" - if f.client_conn.tls_version == "QUIC": + if f.client_conn.tls_version == "QUICv1": if f.type == "tcp": quic_type = "stream" else: diff --git a/mitmproxy/addons/errorcheck.py b/mitmproxy/addons/errorcheck.py index 9b6eff66a1..c46f920354 100644 --- a/mitmproxy/addons/errorcheck.py +++ b/mitmproxy/addons/errorcheck.py @@ -3,6 +3,8 @@ import sys from mitmproxy import log +from mitmproxy.contrib import click as miniclick +from mitmproxy.utils import vt_codes class ErrorCheck: @@ -29,8 +31,13 @@ async def shutdown_if_errored(self): if self.logger.has_errored: plural = "s" if len(self.logger.has_errored) > 1 else "" if self.repeat_errors_on_stderr: - msg = "\n".join(self.logger.format(r) for r in self.logger.has_errored) - print(f"Error{plural} logged during startup:\n{msg}", file=sys.stderr) + message = f"Error{plural} logged during startup:" + if vt_codes.ensure_supported(sys.stderr): # pragma: no cover + message = miniclick.style(message, fg="red") + details = "\n".join( + self.logger.format(r) for r in self.logger.has_errored + ) + print(f"{message}\n{details}", file=sys.stderr) else: print( f"Error{plural} logged during startup, exiting...", file=sys.stderr diff --git a/mitmproxy/addons/export.py b/mitmproxy/addons/export.py index fb5ce2d5db..f1ac553f15 100644 --- a/mitmproxy/addons/export.py +++ b/mitmproxy/addons/export.py @@ -132,7 +132,10 @@ def raw(f: flow.Flow, separator=b"\r\n\r\n") -> bytes: ) if request_present and response_present: - return b"".join([raw_request(f), separator, raw_response(f)]) + parts = [raw_request(f), raw_response(f)] + if isinstance(f, http.HTTPFlow) and f.websocket: + parts.append(f.websocket._get_formatted_messages()) + return separator.join(parts) elif request_present: return raw_request(f) elif response_present: diff --git a/mitmproxy/addons/intercept.py b/mitmproxy/addons/intercept.py index dff16e459d..0749c3b17d 100644 --- a/mitmproxy/addons/intercept.py +++ b/mitmproxy/addons/intercept.py @@ -58,3 +58,6 @@ def dns_request(self, f): def dns_response(self, f): self.process_flow(f) + + def websocket_message(self, f): + self.process_flow(f) diff --git a/mitmproxy/addons/keepserving.py b/mitmproxy/addons/keepserving.py index efe296ab36..04554c9f34 100644 --- a/mitmproxy/addons/keepserving.py +++ b/mitmproxy/addons/keepserving.py @@ -3,6 +3,7 @@ import asyncio from mitmproxy import ctx +from mitmproxy.utils import asyncio_utils class KeepServing: @@ -44,4 +45,6 @@ def running(self): ctx.options.rfile, ] if any(opts) and not ctx.options.keepserving: - self._watch_task = asyncio.get_running_loop().create_task(self.watch()) + self._watch_task = asyncio_utils.create_task( + self.watch(), name="keepserving" + ) diff --git a/mitmproxy/addons/next_layer.py b/mitmproxy/addons/next_layer.py index ce63f81390..8a7ce8f4df 100644 --- a/mitmproxy/addons/next_layer.py +++ b/mitmproxy/addons/next_layer.py @@ -14,11 +14,11 @@ In that case it's not necessary to modify mitmproxy's source, adding a custom addon with a next_layer event hook that sets nextlayer.layer works just as well. """ + from __future__ import annotations import logging import re -import struct import sys from collections.abc import Iterable from collections.abc import Sequence @@ -26,8 +26,7 @@ from typing import cast from mitmproxy import ctx -from mitmproxy import dns -from mitmproxy import exceptions +from mitmproxy.connection import Address from mitmproxy.net.tls import starts_like_dtls_record from mitmproxy.net.tls import starts_like_tls_record from mitmproxy.proxy import layer @@ -47,8 +46,9 @@ from mitmproxy.proxy.layers import TCPLayer from mitmproxy.proxy.layers import UDPLayer from mitmproxy.proxy.layers.http import HTTPMode -from mitmproxy.proxy.layers.quic import quic_parse_client_hello +from mitmproxy.proxy.layers.quic import quic_parse_client_hello_from_datagrams from mitmproxy.proxy.layers.tls import dtls_parse_client_hello +from mitmproxy.proxy.layers.tls import HTTP1_ALPNS from mitmproxy.proxy.layers.tls import HTTP_ALPNS from mitmproxy.proxy.layers.tls import parse_client_hello from mitmproxy.tls import ClientHello @@ -92,10 +92,6 @@ def configure(self, updated): re.compile(x, re.IGNORECASE) for x in ctx.options.udp_hosts ] if "allow_hosts" in updated or "ignore_hosts" in updated: - if ctx.options.allow_hosts and ctx.options.ignore_hosts: - raise exceptions.OptionsError( - "The allow_hosts and ignore_hosts options are mutually exclusive." - ) self.ignore_hosts = [ re.compile(x, re.IGNORECASE) for x in ctx.options.ignore_hosts ] @@ -129,11 +125,11 @@ def s(*layers): udp_based = context.client.transport_protocol == "udp" # 1) check for --ignore/--allow - if self._ignore_connection(context, data_client): + if self._ignore_connection(context, data_client, data_server): return ( - layers.TCPLayer(context, ignore=True) + layers.TCPLayer(context, ignore=not ctx.options.show_ignored_hosts) if tcp_based - else layers.UDPLayer(context, ignore=True) + else layers.UDPLayer(context, ignore=not ctx.options.show_ignored_hosts) ) # 2) Handle proxy modes with well-defined next protocol @@ -157,7 +153,7 @@ def s(*layers): server_tls.child_layer = ClientTLSLayer(context) return server_tls # 3b) QUIC - if udp_based and _starts_like_quic(data_client): + if udp_based and _starts_like_quic(data_client, context.server.address): server_quic = ServerQuicLayer(context) server_quic.child_layer = ClientQuicLayer(context) return server_quic @@ -169,26 +165,30 @@ def s(*layers): return layers.UDPLayer(context) # 5) Handle application protocol - # 5a) Is it DNS? - if udp_based: - try: - # TODO: DNS over TCP - dns.Message.unpack(data_client) # TODO: perf - except struct.error: - pass - else: - return layers.DNSLayer(context) - # 5b) We have no other specialized layers for UDP, so we fall back to raw forwarding. + # 5a) Do we have a known ALPN negotiation? + if context.client.alpn: + if context.client.alpn in HTTP_ALPNS: + return layers.HttpLayer(context, HTTPMode.transparent) + elif context.client.tls_version == "QUICv1": + # TODO: Once we support more QUIC-based protocols, relax force_raw here. + return layers.RawQuicLayer(context, force_raw=True) + # 5b) Is it DNS? + if context.server.address and context.server.address[1] in (53, 5353): + return layers.DNSLayer(context) + # 5c) We have no other specialized layers for UDP, so we fall back to raw forwarding. if udp_based: return layers.UDPLayer(context) - # 5b) Check for raw tcp mode. - very_likely_http = context.client.alpn and context.client.alpn in HTTP_ALPNS - probably_no_http = not very_likely_http and ( + # 5d) Check for raw tcp mode. + probably_no_http = ( # the first three bytes should be the HTTP verb, so A-Za-z is expected. len(data_client) < 3 + # HTTP would require whitespace before the first newline + # if we have neither whitespace nor a newline, it's also unlikely to be HTTP. + or (data_client.find(b" ") >= data_client.find(b"\n")) or not data_client[:3].isalpha() # a server greeting would be uncharacteristic. or data_server + or data_client.startswith(b"SSH") ) if ctx.options.rawtcp and probably_no_http: return layers.TCPLayer(context) @@ -199,6 +199,7 @@ def _ignore_connection( self, context: Context, data_client: bytes, + data_server: bytes, ) -> bool | None: """ Returns: @@ -216,44 +217,87 @@ def _ignore_connection( ) and context.server.address == ("10.0.0.53", 53): return False hostnames: list[str] = [] - if context.server.peername and (peername := context.server.peername[0]): - hostnames.append(peername) - if context.server.address and (server_address := context.server.address[0]): - hostnames.append(server_address) - if ( - client_hello := self._get_client_hello(context, data_client) - ) and client_hello.sni: - hostnames.append(client_hello.sni) - # If the client data is not a TLS record, try to extract the domain from the HTTP request - elif host := self._extract_http1_host_header(data_client): - hostnames.append(host) + if context.server.peername: + host, port, *_ = context.server.peername + hostnames.append(f"{host}:{port}") + if context.server.address: + host, port, *_ = context.server.address + hostnames.append(f"{host}:{port}") + + # We also want to check for TLS SNI and HTTP host headers, but in order to ignore connections based on that + # they must have a destination address. If they don't, we don't know how to establish an upstream connection + # if we ignore. + if host_header := self._get_host_header(context, data_client, data_server): + if not re.search(r":\d+$", host_header): + host_header = f"{host_header}:{port}" + hostnames.append(host_header) + if ( + client_hello := self._get_client_hello(context, data_client) + ) and client_hello.sni: + hostnames.append(f"{client_hello.sni}:{port}") + if context.client.sni: + # Hostname may be allowed, TLS is already established, and we have another next layer decision. + hostnames.append(f"{context.client.sni}:{port}") + if not hostnames: return False - if ctx.options.ignore_hosts: - return any( + if ctx.options.allow_hosts: + not_allowed = not any( re.search(rex, host, re.IGNORECASE) for host in hostnames - for rex in ctx.options.ignore_hosts + for rex in ctx.options.allow_hosts ) - elif ctx.options.allow_hosts: - return not any( + if not_allowed: + return True + + if ctx.options.ignore_hosts: + ignored = any( re.search(rex, host, re.IGNORECASE) for host in hostnames - for rex in ctx.options.allow_hosts + for rex in ctx.options.ignore_hosts ) - else: # pragma: no cover - raise AssertionError() + if ignored: + return True + + return False + + @staticmethod + def _get_host_header( + context: Context, + data_client: bytes, + data_server: bytes, + ) -> str | None: + """ + Try to read a host header from data_client. + + Returns: + The host header value, or None, if no host header was found. + + Raises: + NeedsMoreData, if the HTTP request is incomplete. + """ + if context.client.transport_protocol != "tcp" or data_server: + return None + + host_header_expected = context.client.alpn in HTTP1_ALPNS or re.match( + rb"[A-Z]{3,}.+HTTP/", data_client, re.IGNORECASE + ) + if host_header_expected: + if m := re.search( + rb"\r\n(?:Host:\s+(.+?)\s*)?\r\n", data_client, re.IGNORECASE + ): + if host := m.group(1): + return host.decode("utf-8", "surrogateescape") + else: + return None # \r\n\r\n - header end came first. + else: + raise NeedsMoreData + else: + return None @staticmethod - def _extract_http1_host_header(data_client: bytes) -> str: - pattern = rb"Host:\s+(.+?)\r\n" - match = re.search(pattern, data_client) - return match.group(1).decode() if match else "" - - def _get_client_hello( - self, context: Context, data_client: bytes - ) -> ClientHello | None: + def _get_client_hello(context: Context, data_client: bytes) -> ClientHello | None: """ Try to read a TLS/DTLS/QUIC ClientHello from data_client. @@ -277,7 +321,7 @@ def _get_client_hello( return None case "udp": try: - return quic_parse_client_hello(data_client) + return quic_parse_client_hello_from_datagrams([data_client]) except ValueError: pass @@ -293,7 +337,8 @@ def _get_client_hello( case _: # pragma: no cover assert_never(context.client.transport_protocol) - def _setup_reverse_proxy(self, context: Context, data_client: bytes) -> Layer: + @staticmethod + def _setup_reverse_proxy(context: Context, data_client: bytes) -> Layer: spec = cast(mode_specs.ReverseMode, context.client.proxy_mode) stack = tunnel.LayerStack() @@ -303,10 +348,15 @@ def _setup_reverse_proxy(self, context: Context, data_client: bytes) -> Layer: stack /= ClientTLSLayer(context) stack /= HttpLayer(context, HTTPMode.transparent) case "https": - stack /= ServerTLSLayer(context) - if starts_like_tls_record(data_client): - stack /= ClientTLSLayer(context) - stack /= HttpLayer(context, HTTPMode.transparent) + if context.client.transport_protocol == "udp": + stack /= ServerQuicLayer(context) + stack /= ClientQuicLayer(context) + stack /= HttpLayer(context, HTTPMode.transparent) + else: + stack /= ServerTLSLayer(context) + if starts_like_tls_record(data_client): + stack /= ClientTLSLayer(context) + stack /= HttpLayer(context, HTTPMode.transparent) case "tcp": if starts_like_tls_record(data_client): @@ -346,14 +396,15 @@ def _setup_reverse_proxy(self, context: Context, data_client: bytes) -> Layer: case "quic": stack /= ServerQuicLayer(context) stack /= ClientQuicLayer(context) - stack /= RawQuicLayer(context) + stack /= RawQuicLayer(context, force_raw=True) case _: # pragma: no cover assert_never(spec.scheme) return stack[0] - def _setup_explicit_http_proxy(self, context: Context, data_client: bytes) -> Layer: + @staticmethod + def _setup_explicit_http_proxy(context: Context, data_client: bytes) -> Layer: stack = tunnel.LayerStack() if context.client.transport_protocol == "udp": @@ -368,9 +419,8 @@ def _setup_explicit_http_proxy(self, context: Context, data_client: bytes) -> La return stack[0] - def _is_destination_in_hosts( - self, context: Context, hosts: Iterable[re.Pattern] - ) -> bool: + @staticmethod + def _is_destination_in_hosts(context: Context, hosts: Iterable[re.Pattern]) -> bool: return any( (context.server.address and rex.search(context.server.address[0])) or (context.client.sni and rex.search(context.client.sni)) @@ -378,12 +428,47 @@ def _is_destination_in_hosts( ) -def _starts_like_quic(data_client: bytes) -> bool: - # FIXME: handle clienthellos distributed over multiple packets? - # FIXME: perf - try: - quic_parse_client_hello(data_client) - except ValueError: +# https://www.iana.org/assignments/quic/quic.xhtml +KNOWN_QUIC_VERSIONS = { + 0x00000001, # QUIC v1 + 0x51303433, # Google QUIC Q043 + 0x51303436, # Google QUIC Q046 + 0x51303530, # Google QUIC Q050 + 0x6B3343CF, # QUIC v2 + 0x709A50C4, # QUIC v2 draft codepoint +} + +TYPICAL_QUIC_PORTS = {80, 443, 8443} + + +def _starts_like_quic(data_client: bytes, server_address: Address | None) -> bool: + """ + Make an educated guess on whether this could be QUIC. + This turns out to be quite hard in practice as 1-RTT packets are hardly distinguishable from noise. + + Returns: + True, if the passed bytes could be the start of a QUIC packet. + False, otherwise. + """ + # Minimum size: 1 flag byte + 1+ packet number bytes + 16+ bytes encrypted payload + if len(data_client) < 18: return False + if starts_like_dtls_record(data_client): + return False + # TODO: Add more checks here to detect true negatives. + + # Long Header Packets + if data_client[0] & 0x80: + version = int.from_bytes(data_client[1:5], "big") + if version in KNOWN_QUIC_VERSIONS: + return True + # https://www.rfc-editor.org/rfc/rfc9000.html#name-versions + # Versions that follow the pattern 0x?a?a?a?a are reserved for use in forcing version negotiation + if version & 0x0F0F0F0F == 0x0A0A0A0A: + return True else: - return True + # ¯\_(ツ)_/¯ + # We can't even rely on the QUIC bit, see https://datatracker.ietf.org/doc/rfc9287/. + pass + + return bool(server_address and server_address[1] in TYPICAL_QUIC_PORTS) diff --git a/mitmproxy/addons/proxyauth.py b/mitmproxy/addons/proxyauth.py index 3dcd986194..9250251da3 100644 --- a/mitmproxy/addons/proxyauth.py +++ b/mitmproxy/addons/proxyauth.py @@ -25,9 +25,9 @@ class ProxyAuth: validator: Validator | None = None def __init__(self) -> None: - self.authenticated: MutableMapping[ - connection.Client, tuple[str, str] - ] = weakref.WeakKeyDictionary() + self.authenticated: MutableMapping[connection.Client, tuple[str, str]] = ( + weakref.WeakKeyDictionary() + ) """Contains all connections that are permanently authenticated after an HTTP CONNECT""" def load(self, loader): @@ -76,6 +76,8 @@ def requestheaders(self, f: http.HTTPFlow) -> None: # Is this connection authenticated by a previous HTTP CONNECT? if f.client_conn in self.authenticated: f.metadata["proxyauth"] = self.authenticated[f.client_conn] + elif f.is_replay: + pass else: self.authenticate_http(f) diff --git a/mitmproxy/addons/proxyserver.py b/mitmproxy/addons/proxyserver.py index 42334faaca..644f1fc89f 100644 --- a/mitmproxy/addons/proxyserver.py +++ b/mitmproxy/addons/proxyserver.py @@ -1,6 +1,7 @@ """ This addon is responsible for starting/stopping the proxy server sockets/instances specified by the mode option. """ + from __future__ import annotations import asyncio @@ -33,6 +34,7 @@ from mitmproxy.proxy.mode_servers import ProxyConnectionHandler from mitmproxy.proxy.mode_servers import ServerInstance from mitmproxy.proxy.mode_servers import ServerManager +from mitmproxy.utils import asyncio_utils from mitmproxy.utils import human from mitmproxy.utils import signals @@ -74,6 +76,11 @@ async def update(self, modes: Iterable[mode_specs.ProxyMode]) -> bool: if spec not in new_instances ] + if not start_tasks and not stop_tasks: + return ( + True # nothing to do, so we don't need to trigger `self.changed`. + ) + self._instances = new_instances # Notify listeners about the new not-yet-started servers. await self.changed.send() @@ -114,11 +121,13 @@ class Proxyserver(ServerManager): is_running: bool _connect_addr: Address | None = None _update_task: asyncio.Task | None = None + _inject_tasks: set[asyncio.Task] def __init__(self): self.connections = {} self.servers = Servers(self) self.is_running = False + self._inject_tasks = set() def __repr__(self): return f"Proxyserver({len(self.connections)} active conns)" @@ -250,14 +259,18 @@ def configure(self, updated) -> None: ) # ...and don't listen on the same address. - listen_addrs = [ - ( - m.listen_host(ctx.options.listen_host), - m.listen_port(ctx.options.listen_port), - m.transport_protocol, - ) - for m in modes - ] + listen_addrs = [] + for m in modes: + if m.transport_protocol == "both": + protocols = ["tcp", "udp"] + else: + protocols = [m.transport_protocol] + host = m.listen_host(ctx.options.listen_host) + port = m.listen_port(ctx.options.listen_port) + if port is None: + continue + for proto in protocols: + listen_addrs.append((host, port, proto)) if len(set(listen_addrs)) != len(listen_addrs): (host, port, _) = collections.Counter(listen_addrs).most_common(1)[0][0] dup_addr = human.format_address((host or "0.0.0.0", port)) @@ -276,7 +289,9 @@ def configure(self, updated) -> None: ) if self.is_running: - self._update_task = asyncio.create_task(self.servers.update(modes)) + self._update_task = asyncio_utils.create_task( + self.servers.update(modes), name="update servers" + ) async def setup_servers(self) -> bool: """Setup proxy servers. This may take an indefinite amount of time to complete (e.g. on permission prompts).""" @@ -299,7 +314,15 @@ def inject_event(self, event: events.MessageInjected): ) if connection_id not in self.connections: raise ValueError("Flow is not from a live connection.") - self.connections[connection_id].server_event(event) + + t = asyncio_utils.create_task( + self.connections[connection_id].server_event(event), + name=f"inject_event", + client=event.flow.client_conn.peername, + ) + # Python 3.11 Use TaskGroup instead. + self._inject_tasks.add(t) + t.add_done_callback(self._inject_tasks.remove) @command.command("inject.websocket") def inject_websocket( diff --git a/mitmproxy/addons/readfile.py b/mitmproxy/addons/readfile.py index 63f7b1dbde..1a702a91f0 100644 --- a/mitmproxy/addons/readfile.py +++ b/mitmproxy/addons/readfile.py @@ -11,6 +11,8 @@ from mitmproxy import flowfilter from mitmproxy import io +logger = logging.getLogger(__name__) + class ReadFile: """ @@ -68,9 +70,7 @@ async def doread(self, rfile: str) -> None: try: await self.load_flows_from_path(rfile) except exceptions.FlowReadException as e: - raise exceptions.OptionsError(e) from e - finally: - self._read_task = None + logger.exception(f"Failed to read {ctx.options.rfile}: {e}") def running(self): if ctx.options.rfile: @@ -78,7 +78,7 @@ def running(self): @command.command("readfile.reading") def reading(self) -> bool: - return bool(self._read_task) + return bool(self._read_task and not self._read_task.done()) class ReadFileStdin(ReadFile): diff --git a/mitmproxy/addons/savehar.py b/mitmproxy/addons/savehar.py index 5e3f22ad48..999171248a 100644 --- a/mitmproxy/addons/savehar.py +++ b/mitmproxy/addons/savehar.py @@ -1,4 +1,5 @@ """Write flow objects to a HAR file""" + import base64 import json import logging @@ -144,11 +145,11 @@ def flow_entry(self, flow: http.HTTPFlow, servers_seen: set[Server]) -> dict: - flow.server_conn.timestamp_tcp_setup ) else: - ssl_time = None + ssl_time = -1.0 servers_seen.add(flow.server_conn) else: - connect_time = None - ssl_time = None + connect_time = -1.0 + ssl_time = -1.0 if flow.request.timestamp_end: send = 1000 * (flow.request.timestamp_end - flow.request.timestamp_start) @@ -227,6 +228,11 @@ def flow_entry(self, flow: http.HTTPFlow, servers_seen: set[Server]) -> dict: if flow.error: response["_error"] = flow.error.msg + if flow.request.method == "CONNECT": + url = f"https://{flow.request.pretty_url}/" + else: + url = flow.request.pretty_url + entry: dict[str, Any] = { "startedDateTime": datetime.fromtimestamp( flow.request.timestamp_start, timezone.utc @@ -234,7 +240,7 @@ def flow_entry(self, flow: http.HTTPFlow, servers_seen: set[Server]) -> dict: "time": sum(v for v in timings.values() if v is not None and v >= 0), "request": { "method": flow.request.method, - "url": flow.request.pretty_url, + "url": url, "httpVersion": flow.request.http_version, "cookies": self.format_multidict(flow.request.cookies), "headers": self.format_multidict(flow.request.headers), diff --git a/mitmproxy/addons/script.py b/mitmproxy/addons/script.py index a9b864cc8e..69a7bc805d 100644 --- a/mitmproxy/addons/script.py +++ b/mitmproxy/addons/script.py @@ -128,6 +128,9 @@ def loadscript(self): ctx.master.addons.invoke_addon_sync(self.ns, hooks.RunningHook()) async def watcher(self): + # Script loading is terminally confused at the moment. + # This here is a stopgap workaround to defer loading. + await asyncio.sleep(0) last_mtime = 0.0 while True: try: diff --git a/mitmproxy/addons/serverplayback.py b/mitmproxy/addons/serverplayback.py index 077eade378..c5b13b1a20 100644 --- a/mitmproxy/addons/serverplayback.py +++ b/mitmproxy/addons/serverplayback.py @@ -16,6 +16,15 @@ logger = logging.getLogger(__name__) +HASH_OPTIONS = [ + "server_replay_ignore_content", + "server_replay_ignore_host", + "server_replay_ignore_params", + "server_replay_ignore_payload_params", + "server_replay_ignore_port", + "server_replay_use_headers", +] + class ServerPlayback: flowmap: dict[Hashable, list[http.HTTPFlow]] @@ -255,6 +264,16 @@ def configure(self, updated): except exceptions.FlowReadException as e: raise exceptions.OptionsError(str(e)) self.load_flows(flows) + if any(option in updated for option in HASH_OPTIONS): + self.recompute_hashes() + + def recompute_hashes(self) -> None: + """ + Rebuild flowmap if the hashing method has changed during execution, + see https://github.com/mitmproxy/mitmproxy/issues/4506 + """ + flows = [flow for lst in self.flowmap.values() for flow in lst] + self.load_flows(flows) def request(self, f: http.HTTPFlow) -> None: if self.flowmap: diff --git a/mitmproxy/addons/stickycookie.py b/mitmproxy/addons/stickycookie.py index 2164ac55f0..11b4773bf5 100644 --- a/mitmproxy/addons/stickycookie.py +++ b/mitmproxy/addons/stickycookie.py @@ -34,9 +34,9 @@ def domain_match(a: str, b: str) -> bool: class StickyCookie: def __init__(self) -> None: - self.jar: collections.defaultdict[ - TOrigin, dict[str, str] - ] = collections.defaultdict(dict) + self.jar: collections.defaultdict[TOrigin, dict[str, str]] = ( + collections.defaultdict(dict) + ) self.flt: flowfilter.TFilter | None = None def load(self, loader): diff --git a/mitmproxy/addons/strip_dns_https_records.py b/mitmproxy/addons/strip_dns_https_records.py new file mode 100644 index 0000000000..b43383426d --- /dev/null +++ b/mitmproxy/addons/strip_dns_https_records.py @@ -0,0 +1,37 @@ +from mitmproxy import ctx +from mitmproxy import dns +from mitmproxy.net.dns import types + + +class StripDnsHttpsRecords: + def load(self, loader): + loader.add_option( + "strip_ech", + bool, + True, + "Strip Encrypted ClientHello (ECH) data from DNS HTTPS records so that mitmproxy can generate matching certificates.", + ) + + def dns_response(self, flow: dns.DNSFlow): + assert flow.response + if ctx.options.strip_ech: + for answer in flow.response.answers: + if answer.type == types.HTTPS: + answer.https_ech = None + if not ctx.options.http3: + for answer in flow.response.answers: + if ( + answer.type == types.HTTPS + and answer.https_alpn is not None + and any( + # HTTP/3 or any of the spec drafts (h3-...)? + a == b"h3" or a.startswith(b"h3-") + for a in answer.https_alpn + ) + ): + alpns = tuple( + a + for a in answer.https_alpn + if a != b"h3" and not a.startswith(b"h3-") + ) + answer.https_alpn = alpns or None diff --git a/mitmproxy/addons/tlsconfig.py b/mitmproxy/addons/tlsconfig.py index e044d1d1c8..eda94798b1 100644 --- a/mitmproxy/addons/tlsconfig.py +++ b/mitmproxy/addons/tlsconfig.py @@ -8,6 +8,7 @@ from aioquic.h3.connection import H3_ALPN from aioquic.tls import CipherSuite +from cryptography import x509 from OpenSSL import crypto from OpenSSL import SSL @@ -23,6 +24,8 @@ from mitmproxy.proxy.layers import quic from mitmproxy.proxy.layers import tls as proxy_tls +logger = logging.getLogger(__name__) + # We manually need to specify this, otherwise OpenSSL may select a non-HTTP2 cipher by default. # https://ssl-config.mozilla.org/#config=old @@ -157,6 +160,12 @@ def load(self, loader): help="Use a specific elliptic curve for ECDHE key exchange on server connections. " 'OpenSSL syntax, for example "prime256v1" (see `openssl ecparam -list_curves`).', ) + loader.add_option( + name="request_client_cert", + typespec=bool, + default=False, + help=f"Requests a client certificate (TLS message 'CertificateRequest') to establish a mutual TLS connection between client and mitmproxy (combined with 'client_certs' option for mitmproxy and upstream).", + ) def tls_clienthello(self, tls_clienthello: tls.ClientHelloData): conn_context = tls_clienthello.context @@ -196,7 +205,7 @@ def tls_start_client(self, tls_start: tls.TlsData) -> None: cipher_list=tuple(cipher_list), ecdh_curve=ctx.options.tls_ecdh_curve_client, chain_file=entry.chain_file, - request_client_cert=False, + request_client_cert=ctx.options.request_client_cert, alpn_select_callback=alpn_select_callback, extra_chain_certs=tuple(extra_chain_certs), dhparams=self.certstore.dhparams, @@ -440,7 +449,7 @@ def configure(self, updated): else None, ) if self.certstore.default_ca.has_expired(): - logging.warning( + logger.warning( "The mitmproxy certificate authority has expired!\n" "Please delete all CA-related files in your ~/.mitmproxy folder.\n" "The CA will be regenerated automatically after restarting mitmproxy.\n" @@ -483,36 +492,75 @@ def configure(self, updated): f"Invalid ECDH curve: {ecdh_curve!r}" ) from e + if "tls_version_client_min" in updated: + self._warn_unsupported_version("tls_version_client_min", True) + if "tls_version_client_max" in updated: + self._warn_unsupported_version("tls_version_client_max", False) + if "tls_version_server_min" in updated: + self._warn_unsupported_version("tls_version_server_min", True) + if "tls_version_server_max" in updated: + self._warn_unsupported_version("tls_version_server_max", False) + + def _warn_unsupported_version(self, attribute: str, warn_unbound: bool): + val = net_tls.Version[getattr(ctx.options, attribute)] + supported_versions = [ + v for v in net_tls.Version if net_tls.is_supported_version(v) + ] + supported_versions_str = ", ".join(v.name for v in supported_versions) + + if val is net_tls.Version.UNBOUNDED: + if warn_unbound: + logger.info( + f"{attribute} has been set to {val.name}. Note that your " + f"OpenSSL build only supports the following TLS versions: {supported_versions_str}" + ) + elif val not in supported_versions: + logger.warning( + f"{attribute} has been set to {val.name}, which is not supported by the current OpenSSL build. " + f"The current build only supports the following versions: {supported_versions_str}" + ) + def get_cert(self, conn_context: context.Context) -> certs.CertStoreEntry: """ This function determines the Common Name (CN), Subject Alternative Names (SANs) and Organization Name our certificate should have and then fetches a matching cert from the certstore. """ - altnames: list[str] = [] + altnames: list[x509.GeneralName] = [] organization: str | None = None # Use upstream certificate if available. if ctx.options.upstream_cert and conn_context.server.certificate_list: upstream_cert = conn_context.server.certificate_list[0] if upstream_cert.cn: - altnames.append(upstream_cert.cn) + altnames.append(_ip_or_dns_name(upstream_cert.cn)) altnames.extend(upstream_cert.altnames) if upstream_cert.organization: organization = upstream_cert.organization # Add SNI or our local IP address. if conn_context.client.sni: - altnames.append(conn_context.client.sni) + altnames.append(_ip_or_dns_name(conn_context.client.sni)) else: - altnames.append(conn_context.client.sockname[0]) + altnames.append(_ip_or_dns_name(conn_context.client.sockname[0])) # If we already know of a server address, include that in the SANs as well. if conn_context.server.address: - altnames.append(conn_context.server.address[0]) + altnames.append(_ip_or_dns_name(conn_context.server.address[0])) # only keep first occurrence of each hostname altnames = list(dict.fromkeys(altnames)) # RFC 2818: If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. # In other words, the Common Name is irrelevant then. - return self.certstore.get_cert(altnames[0], altnames, organization) + cn = next((str(x.value) for x in altnames), None) + return self.certstore.get_cert(cn, altnames, organization) + + +def _ip_or_dns_name(val: str) -> x509.GeneralName: + """Convert a string into either an x509.IPAddress or x509.DNSName object.""" + try: + ip = ipaddress.ip_address(val) + except ValueError: + return x509.DNSName(val.encode("idna").decode()) + else: + return x509.IPAddress(ip) diff --git a/mitmproxy/addons/update_alt_svc.py b/mitmproxy/addons/update_alt_svc.py new file mode 100644 index 0000000000..fa514e28b1 --- /dev/null +++ b/mitmproxy/addons/update_alt_svc.py @@ -0,0 +1,33 @@ +import re + +from mitmproxy import ctx +from mitmproxy.http import HTTPFlow +from mitmproxy.proxy import mode_specs + +ALT_SVC = "alt-svc" +HOST_PATTERN = r"([a-zA-Z0-9.-]*:\d{1,5})" + + +def update_alt_svc_header(header: str, port: int) -> str: + return re.sub(HOST_PATTERN, f":{port}", header) + + +class UpdateAltSvc: + def load(self, loader): + loader.add_option( + "keep_alt_svc_header", + bool, + False, + "Reverse Proxy: Keep Alt-Svc headers as-is, even if they do not point to mitmproxy. Enabling this option may cause clients to bypass the proxy.", + ) + + def responseheaders(self, flow: HTTPFlow): + assert flow.response + if ( + not ctx.options.keep_alt_svc_header + and isinstance(flow.client_conn.proxy_mode, mode_specs.ReverseMode) + and ALT_SVC in flow.response.headers + ): + _, listen_port, *_ = flow.client_conn.sockname + headers = flow.response.headers + headers[ALT_SVC] = update_alt_svc_header(headers[ALT_SVC], listen_port) diff --git a/mitmproxy/addons/view.py b/mitmproxy/addons/view.py index 6c0c286cd4..5561be5720 100644 --- a/mitmproxy/addons/view.py +++ b/mitmproxy/addons/view.py @@ -8,6 +8,7 @@ - Exposes a settings store for flows that automatically expires if the flow is removed from the store. """ + import collections import logging import re @@ -136,20 +137,18 @@ def generate(self, f: mitmproxy.flow.Flow) -> int: ] -def _signal_with_flow(flow: mitmproxy.flow.Flow) -> None: - ... +def _signal_with_flow(flow: mitmproxy.flow.Flow) -> None: ... -def _sig_view_remove(flow: mitmproxy.flow.Flow, index: int) -> None: - ... +def _sig_view_remove(flow: mitmproxy.flow.Flow, index: int) -> None: ... class View(collections.abc.Sequence): def __init__(self) -> None: super().__init__() - self._store: collections.OrderedDict[ - str, mitmproxy.flow.Flow - ] = collections.OrderedDict() + self._store: collections.OrderedDict[str, mitmproxy.flow.Flow] = ( + collections.OrderedDict() + ) self.filter = flowfilter.match_all # Should we show only marked flows? self.show_marked = False diff --git a/mitmproxy/certs.py b/mitmproxy/certs.py index d994fbb6b6..a5a81ea1ae 100644 --- a/mitmproxy/certs.py +++ b/mitmproxy/certs.py @@ -1,9 +1,11 @@ import contextlib import datetime import ipaddress +import logging import os -import re import sys +import warnings +from collections.abc import Iterable from dataclasses import dataclass from pathlib import Path from typing import cast @@ -18,12 +20,15 @@ from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.types import CertificatePublicKeyTypes from cryptography.hazmat.primitives.serialization import pkcs12 from cryptography.x509 import ExtendedKeyUsageOID from cryptography.x509 import NameOID from mitmproxy.coretypes import serializable +logger = logging.getLogger(__name__) + # Default expiry must not be too long: https://github.com/mitmproxy/mitmproxy/issues/815 CA_EXPIRY = datetime.timedelta(days=10 * 365) CERT_EXPIRY = datetime.timedelta(days=365) @@ -59,7 +64,8 @@ def __eq__(self, other): return self.fingerprint() == other.fingerprint() def __repr__(self): - return f"" + altnames = [str(x.value) for x in self.altnames] + return f"" def __hash__(self): return self._cert.__hash__() @@ -89,6 +95,9 @@ def from_pyopenssl(self, x509: OpenSSL.crypto.X509) -> "Cert": def to_pyopenssl(self) -> OpenSSL.crypto.X509: return OpenSSL.crypto.X509.from_cryptography(self._cert) + def public_key(self) -> CertificatePublicKeyTypes: + return self._cert.public_key() + def fingerprint(self) -> bytes: return self._cert.fingerprint(hashes.SHA256()) @@ -98,16 +107,24 @@ def issuer(self) -> list[tuple[str, str]]: @property def notbefore(self) -> datetime.datetime: - # x509.Certificate.not_valid_before is a naive datetime in UTC - return self._cert.not_valid_before.replace(tzinfo=datetime.timezone.utc) + try: + # type definitions haven't caught up with new API yet. + return self._cert.not_valid_before_utc # type: ignore + except AttributeError: # pragma: no cover + # cryptography < 42.0 + return self._cert.not_valid_before.replace(tzinfo=datetime.timezone.utc) @property def notafter(self) -> datetime.datetime: - # x509.Certificate.not_valid_after is a naive datetime in UTC - return self._cert.not_valid_after.replace(tzinfo=datetime.timezone.utc) + try: + return self._cert.not_valid_after_utc # type: ignore + except AttributeError: # pragma: no cover + return self._cert.not_valid_after.replace(tzinfo=datetime.timezone.utc) def has_expired(self) -> bool: - return datetime.datetime.utcnow() > self._cert.not_valid_after + if sys.version_info < (3, 11): # pragma: no cover + return datetime.datetime.now(datetime.timezone.utc) > self.notafter + return datetime.datetime.now(datetime.UTC) > self.notafter @property def subject(self) -> list[tuple[str, str]]: @@ -117,6 +134,17 @@ def subject(self) -> list[tuple[str, str]]: def serial(self) -> int: return self._cert.serial_number + @property + def is_ca(self) -> bool: + constraints: x509.BasicConstraints + try: + constraints = self._cert.extensions.get_extension_for_class( + x509.BasicConstraints + ).value + return constraints.ca + except x509.ExtensionNotFound: + return False + @property def keyinfo(self) -> tuple[str, int]: public_key = self._cert.public_key() @@ -148,20 +176,18 @@ def organization(self) -> str | None: return None @property - def altnames(self) -> list[str]: + def altnames(self) -> x509.GeneralNames: """ Get all SubjectAlternativeName DNS altnames. """ try: - ext = self._cert.extensions.get_extension_for_class( + sans = self._cert.extensions.get_extension_for_class( x509.SubjectAlternativeName ).value except x509.ExtensionNotFound: - return [] + return x509.GeneralNames([]) else: - return ext.get_values_for_type(x509.DNSName) + [ - str(x) for x in ext.get_values_for_type(x509.IPAddress) - ] + return x509.GeneralNames(sans) def _name_to_keyval(name: x509.Name) -> list[tuple[str, str]]: @@ -225,11 +251,41 @@ def create_ca( return private_key, cert +def _fix_legacy_sans(sans: Iterable[x509.GeneralName] | list[str]) -> x509.GeneralNames: + """ + SANs used to be a list of strings in mitmproxy 10.1 and below, but now they're a list of GeneralNames. + This function converts the old format to the new one. + """ + if isinstance(sans, x509.GeneralNames): + return sans + elif ( + isinstance(sans, list) and len(sans) > 0 and isinstance(sans[0], str) + ): # pragma: no cover + warnings.warn( + "Passing SANs as a list of strings is deprecated.", + DeprecationWarning, + stacklevel=2, + ) + + ss: list[x509.GeneralName] = [] + for x in cast(list[str], sans): + try: + ip = ipaddress.ip_address(x) + except ValueError: + x = x.encode("idna").decode() + ss.append(x509.DNSName(x)) + else: + ss.append(x509.IPAddress(ip)) + return x509.GeneralNames(ss) + else: + return x509.GeneralNames(sans) + + def dummy_cert( privkey: rsa.RSAPrivateKey, cacert: x509.Certificate, commonname: str | None, - sans: list[str], + sans: Iterable[x509.GeneralName], organization: str | None = None, ) -> Cert: """ @@ -265,31 +321,21 @@ def dummy_cert( builder = builder.subject_name(x509.Name(subject)) builder = builder.serial_number(x509.random_serial_number()) - ss: list[x509.GeneralName] = [] - for x in sans: - try: - ip = ipaddress.ip_address(x) - except ValueError: - x = x.encode("idna").decode() - ss.append(x509.DNSName(x)) - else: - ss.append(x509.IPAddress(ip)) # RFC 5280 §4.2.1.6: subjectAltName is critical if subject is empty. builder = builder.add_extension( - x509.SubjectAlternativeName(ss), critical=not is_valid_commonname + x509.SubjectAlternativeName(_fix_legacy_sans(sans)), + critical=not is_valid_commonname, ) - # we just use the same key as the CA for these certs, so put that in the SKI extension - builder = builder.add_extension( - x509.SubjectKeyIdentifier.from_public_key(privkey.public_key()), - critical=False, - ) - # add authority key identifier for the cacert issuing cert for greater acceptance by - # client TLS libraries (such as OpenSSL 3.x) + # https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.1 builder = builder.add_extension( x509.AuthorityKeyIdentifier.from_issuer_public_key(cacert.public_key()), critical=False, ) + # If CA and leaf cert have the same Subject Key Identifier, SChannel breaks in funny ways, + # see https://github.com/mitmproxy/mitmproxy/issues/6494. + # https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2 states + # that SKI is optional for the leaf cert, so we skip that. cert = builder.sign(private_key=privkey, algorithm=hashes.SHA256()) # type: ignore return Cert(cert) @@ -304,7 +350,7 @@ class CertStoreEntry: TCustomCertId = str # manually provided certs (e.g. mitmproxy's --certs) -TGeneratedCertId = tuple[Optional[str], tuple[str, ...]] # (common_name, sans) +TGeneratedCertId = tuple[Optional[str], x509.GeneralNames] # (common_name, sans) TCertId = Union[TCustomCertId, TGeneratedCertId] DHParams = NewType("DHParams", bytes) @@ -330,14 +376,7 @@ def __init__( self.default_ca = default_ca self.default_chain_file = default_chain_file self.default_chain_certs = ( - [ - Cert.from_pem(chunk) - for chunk in re.split( - rb"(?=-----BEGIN( [A-Z]+)+-----)", - self.default_chain_file.read_bytes(), - ) - if chunk.startswith(b"-----BEGIN CERTIFICATE-----") - ] + x509.load_pem_x509_certificates(self.default_chain_file.read_bytes()) if self.default_chain_file else [default_ca] ) @@ -397,9 +436,9 @@ def from_files( raw = ca_file.read_bytes() key = load_pem_private_key(raw, passphrase) dh = cls.load_dhparam(dhparam_file) - certs = re.split(rb"(?=-----BEGIN CERTIFICATE-----)", raw) - ca = Cert.from_pem(certs[1]) - if len(certs) > 2: + certs = x509.load_pem_x509_certificates(raw) + ca = Cert(certs[0]) + if len(certs) > 1: chain_file: Path | None = ca_file else: chain_file = None @@ -481,11 +520,34 @@ def add_cert_file( raw = path.read_bytes() cert = Cert.from_pem(raw) try: - key = load_pem_private_key(raw, password=passphrase) - except ValueError: - key = self.default_privatekey + private_key = load_pem_private_key(raw, password=passphrase) + except ValueError as e: + private_key = self.default_privatekey + if cert.public_key() != private_key.public_key(): + raise ValueError( + f'Unable to find private key in "{path.absolute()}": {e}' + ) from e + else: + if cert.public_key() != private_key.public_key(): + raise ValueError( + f'Private and public keys in "{path.absolute()}" do not match:\n' + f"{cert.public_key()=}\n" + f"{private_key.public_key()=}" + ) - self.add_cert(CertStoreEntry(cert, key, path, [cert]), spec) + try: + chain = [Cert(x) for x in x509.load_pem_x509_certificates(raw)] + except ValueError as e: + logger.warning(f"Failed to read certificate chain: {e}") + chain = [cert] + + if cert.is_ca: + logger.warning( + f'"{path.absolute()}" is a certificate authority and not a leaf certificate. ' + f"This indicates a misconfiguration, see https://docs.mitmproxy.org/stable/concepts-certificates/." + ) + + self.add_cert(CertStoreEntry(cert, private_key, path, chain), spec) def add_cert(self, entry: CertStoreEntry, *names: str) -> None: """ @@ -495,26 +557,31 @@ def add_cert(self, entry: CertStoreEntry, *names: str) -> None: if entry.cert.cn: self.certs[entry.cert.cn] = entry for i in entry.cert.altnames: - self.certs[i] = entry + self.certs[str(i.value)] = entry for i in names: self.certs[i] = entry @staticmethod - def asterisk_forms(dn: str) -> list[str]: + def asterisk_forms(dn: str | x509.GeneralName) -> list[str]: """ Return all asterisk forms for a domain. For example, for www.example.com this will return [b"www.example.com", b"*.example.com", b"*.com"]. The single wildcard "*" is omitted. """ - parts = dn.split(".") - ret = [dn] - for i in range(1, len(parts)): - ret.append("*." + ".".join(parts[i:])) - return ret + if isinstance(dn, str): + parts = dn.split(".") + ret = [dn] + for i in range(1, len(parts)): + ret.append("*." + ".".join(parts[i:])) + return ret + elif isinstance(dn, x509.DNSName): + return CertStore.asterisk_forms(dn.value) + else: + return [str(dn.value)] def get_cert( self, commonname: str | None, - sans: list[str], + sans: Iterable[x509.GeneralName], organization: str | None = None, ) -> CertStoreEntry: """ @@ -525,6 +592,7 @@ def get_cert( organization: Organization name for the generated certificate. """ + sans = _fix_legacy_sans(sans) potential_keys: list[TCertId] = [] if commonname: @@ -532,7 +600,7 @@ def get_cert( for s in sans: potential_keys.extend(self.asterisk_forms(s)) potential_keys.append("*") - potential_keys.append((commonname, tuple(sans))) + potential_keys.append((commonname, sans)) name = next(filter(lambda key: key in self.certs, potential_keys), None) if name: @@ -550,7 +618,7 @@ def get_cert( chain_file=self.default_chain_file, chain_certs=self.default_chain_certs, ) - self.certs[(commonname, tuple(sans))] = entry + self.certs[(commonname, sans)] = entry self.expire(entry) return entry diff --git a/mitmproxy/command.py b/mitmproxy/command.py index 5b12497e13..822c40eb64 100644 --- a/mitmproxy/command.py +++ b/mitmproxy/command.py @@ -1,6 +1,7 @@ """ - This module manages and invokes typed commands. +This module manages and invokes typed commands. """ + import functools import inspect import logging diff --git a/mitmproxy/connection.py b/mitmproxy/connection.py index dfa474d0d1..7215a7a794 100644 --- a/mitmproxy/connection.py +++ b/mitmproxy/connection.py @@ -27,6 +27,18 @@ class ConnectionState(Flag): TransportProtocol = Literal["tcp", "udp"] +# https://docs.openssl.org/master/man3/SSL_get_version/#return-values +TlsVersion = Literal[ + "SSLv3", + "TLSv1", + "TLSv1.1", + "TLSv1.2", + "TLSv1.3", + "DTLSv0.9", + "DTLSv1", + "DTLSv1.2", + "QUICv1", +] # practically speaking we may have IPv6 addresses with flowinfo and scope_id, # but type checking isn't good enough to properly handle tuple unions. @@ -104,7 +116,7 @@ class Connection(serializable.SerializableDataclass, metaclass=ABCMeta): """The active cipher name as returned by OpenSSL's `SSL_CIPHER_get_name`.""" cipher_list: Sequence[str] = () """Ciphers accepted by the proxy server on this connection.""" - tls_version: str | None = None + tls_version: TlsVersion | None = None """The active TLS version.""" sni: str | None = None """ diff --git a/mitmproxy/contentviews/__init__.py b/mitmproxy/contentviews/__init__.py index ec2313751f..399b3e0b65 100644 --- a/mitmproxy/contentviews/__init__.py +++ b/mitmproxy/contentviews/__init__.py @@ -11,6 +11,7 @@ metadata depend on the protocol in use. Known attributes can be found in `base.View`. """ + import traceback from ..tcp import TCPMessage @@ -50,8 +51,7 @@ views: list[View] = [] -def _update(view: View) -> None: - ... +def _update(view: View) -> None: ... on_add = signals.SyncSignal(_update) @@ -141,6 +141,10 @@ def get_message_content_view( if isinstance(message, UDPMessage): udp_message = message + websocket_message = None + if isinstance(message, WebSocketMessage): + websocket_message = message + description, lines, error = get_content_view( viewmode, content, @@ -149,6 +153,7 @@ def get_message_content_view( http_message=http_message, tcp_message=tcp_message, udp_message=udp_message, + websocket_message=websocket_message, ) if enc: @@ -166,6 +171,7 @@ def get_content_view( http_message: http.Message | None = None, tcp_message: tcp.TCPMessage | None = None, udp_message: udp.UDPMessage | None = None, + websocket_message: WebSocketMessage | None = None, ): """ Args: @@ -186,6 +192,7 @@ def get_content_view( http_message=http_message, tcp_message=tcp_message, udp_message=udp_message, + websocket_message=websocket_message, ) if ret is None: ret = ( @@ -197,6 +204,7 @@ def get_content_view( http_message=http_message, tcp_message=tcp_message, udp_message=udp_message, + websocket_message=websocket_message, )[1], ) desc, content = ret @@ -213,6 +221,7 @@ def get_content_view( http_message=http_message, tcp_message=tcp_message, udp_message=udp_message, + websocket_message=websocket_message, )[1] error = f"{getattr(viewmode, 'name')} content viewer failed: \n{traceback.format_exc()}" diff --git a/mitmproxy/contentviews/graphql.py b/mitmproxy/contentviews/graphql.py index 5263b75f5f..b76b7bf054 100644 --- a/mitmproxy/contentviews/graphql.py +++ b/mitmproxy/contentviews/graphql.py @@ -30,7 +30,12 @@ def is_graphql_query(data): def is_graphql_batch_query(data): - return isinstance(data, list) and isinstance(data[0], dict) and "query" in data[0] + return ( + isinstance(data, list) + and len(data) > 0 + and isinstance(data[0], dict) + and "query" in data[0] + ) class ViewGraphQL(base.View): diff --git a/mitmproxy/contentviews/multipart.py b/mitmproxy/contentviews/multipart.py index 6114fff653..450b427411 100644 --- a/mitmproxy/contentviews/multipart.py +++ b/mitmproxy/contentviews/multipart.py @@ -1,3 +1,4 @@ +from .. import http from . import base from mitmproxy.coretypes import multidict from mitmproxy.net.http import multipart @@ -11,7 +12,17 @@ def _format(v): yield [("highlight", "Form data:\n")] yield from base.format_dict(multidict.MultiDict(v)) - def __call__(self, data: bytes, content_type: str | None = None, **metadata): + def __call__( + self, + data: bytes, + content_type: str | None = None, + http_message: http.Message | None = None, + **metadata, + ): + # The content_type doesn't have the boundary, so we get it from the header again + headers = getattr(http_message, "headers", None) + if headers: + content_type = headers.get("content-type") if content_type is None: return v = multipart.decode_multipart(content_type, data) diff --git a/mitmproxy/coretypes/bidi.py b/mitmproxy/coretypes/bidi.py index 943062898c..5423f68c9c 100644 --- a/mitmproxy/coretypes/bidi.py +++ b/mitmproxy/coretypes/bidi.py @@ -1,5 +1,4 @@ class BiDi: - """ A wee utility class for keeping bi-directional mappings, like field constants in protocols. Names are attributes on the object, dict-like diff --git a/mitmproxy/ctx.py b/mitmproxy/ctx.py index 8380a100be..e83983a4cb 100644 --- a/mitmproxy/ctx.py +++ b/mitmproxy/ctx.py @@ -7,6 +7,8 @@ import mitmproxy.master import mitmproxy.options -log: mitmproxy.log.Log master: mitmproxy.master.Master options: mitmproxy.options.Options + +log: mitmproxy.log.Log +"""Deprecated: Use Python's builtin `logging` module instead.""" diff --git a/mitmproxy/dns.py b/mitmproxy/dns.py index 5372f8dff0..cd79cdcb2b 100644 --- a/mitmproxy/dns.py +++ b/mitmproxy/dns.py @@ -1,9 +1,11 @@ from __future__ import annotations +import base64 import itertools import random import struct import time +from collections.abc import Iterable from dataclasses import dataclass from ipaddress import IPv4Address from ipaddress import IPv6Address @@ -13,9 +15,12 @@ from mitmproxy.coretypes import serializable from mitmproxy.net.dns import classes from mitmproxy.net.dns import domain_names +from mitmproxy.net.dns import https_records from mitmproxy.net.dns import op_codes from mitmproxy.net.dns import response_codes from mitmproxy.net.dns import types +from mitmproxy.net.dns.https_records import HTTPSRecord +from mitmproxy.net.dns.https_records import SVCParamKeys # DNS parameters taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xml @@ -64,6 +69,8 @@ def __str__(self) -> str: return self.domain_name if self.type == types.TXT: return self.text + if self.type == types.HTTPS: + return str(https_records.unpack(self.data)) except Exception: return f"0x{self.data.hex()} (invalid {types.to_str(self.type)} data)" return f"0x{self.data.hex()}" @@ -100,6 +107,50 @@ def domain_name(self) -> str: def domain_name(self, name: str) -> None: self.data = domain_names.pack(name) + @property + def https_alpn(self) -> tuple[bytes, ...] | None: + record = https_records.unpack(self.data) + alpn_bytes = record.params.get(SVCParamKeys.ALPN.value, None) + if alpn_bytes is not None: + i = 0 + ret = [] + while i < len(alpn_bytes): + token_len = alpn_bytes[i] + ret.append(alpn_bytes[i + 1 : i + 1 + token_len]) + i += token_len + 1 + return tuple(ret) + else: + return None + + @https_alpn.setter + def https_alpn(self, alpn: Iterable[bytes] | None) -> None: + record = https_records.unpack(self.data) + if alpn is None: + record.params.pop(SVCParamKeys.ALPN.value, None) + else: + alpn_bytes = b"".join(bytes([len(a)]) + a for a in alpn) + record.params[SVCParamKeys.ALPN.value] = alpn_bytes + self.data = https_records.pack(record) + + @property + def https_ech(self) -> str | None: + record = https_records.unpack(self.data) + ech_bytes = record.params.get(SVCParamKeys.ECH.value, None) + if ech_bytes is not None: + return base64.b64encode(ech_bytes).decode("utf-8") + else: + return None + + @https_ech.setter + def https_ech(self, ech: str | None) -> None: + record = https_records.unpack(self.data) + if ech is None: + record.params.pop(SVCParamKeys.ECH.value, None) + else: + ech_bytes = base64.b64decode(ech.encode("utf-8")) + record.params[SVCParamKeys.ECH.value] = ech_bytes + self.data = https_records.pack(record) + def to_json(self) -> dict: """ Converts the resource record into json for mitmweb. @@ -142,6 +193,13 @@ def TXT(cls, name: str, text: str, *, ttl: int = DEFAULT_TTL) -> ResourceRecord: """Create a textual resource record.""" return cls(name, types.TXT, classes.IN, ttl, text.encode("utf-8")) + @classmethod + def HTTPS( + cls, name: str, record: HTTPSRecord, ttl: int = DEFAULT_TTL + ) -> ResourceRecord: + """Create a HTTPS resource record""" + return cls(name, types.HTTPS, classes.IN, ttl, https_records.pack(record)) + # comments are taken from rfc1035 @dataclass @@ -204,6 +262,14 @@ def content(self) -> bytes: """Returns the user-friendly content of all parts as encoded bytes.""" return str(self).encode() + @property + def question(self) -> Question | None: + """DNS practically only supports a single question at the + same time, so this is a shorthand for this.""" + if len(self.questions) == 1: + return self.questions[0] + return None + @property def size(self) -> int: """Returns the cumulative data size of all resource record sections.""" @@ -324,19 +390,12 @@ def unpack_rrs( f"unpack requires a data buffer of {len_data} bytes" ) data = buffer[offset:end_data] - if 0b11000000 in data: - # the resource record might contains a compressed domain name, if so, uncompressed in advance - try: - ( - rr_name, - rr_name_len, - ) = domain_names.unpack_from_with_compression( - buffer, offset, cached_names - ) - if rr_name_len == len_data: - data = domain_names.pack(rr_name) - except struct.error: - pass + + if domain_names.record_data_can_have_compression(type): + data = domain_names.decompress_from_record_data( + buffer, offset, end_data, cached_names + ) + section.append(ResourceRecord(name, type, class_, ttl, data)) offset += len_data except struct.error as e: diff --git a/mitmproxy/flowfilter.py b/mitmproxy/flowfilter.py index 52db22be03..b9a6f286c3 100644 --- a/mitmproxy/flowfilter.py +++ b/mitmproxy/flowfilter.py @@ -1,37 +1,38 @@ """ - The following operators are understood: - - ~q Request - ~s Response - - Headers: - - Patterns are matched against "name: value" strings. Field names are - all-lowercase. - - ~a Asset content-type in response. Asset content types are: - text/javascript - application/x-javascript - application/javascript - text/css - image/* - font/* - application/font-* - ~h rex Header line in either request or response - ~hq rex Header in request - ~hs rex Header in response - - ~b rex Expression in the body of either request or response - ~bq rex Expression in the body of request - ~bs rex Expression in the body of response - ~t rex Shortcut for content-type header. - - ~d rex Request domain - ~m rex Method - ~u rex URL - ~c CODE Response code. - rex Equivalent to ~u rex +The following operators are understood: + + ~q Request + ~s Response + +Headers: + + Patterns are matched against "name: value" strings. Field names are + all-lowercase. + + ~a Asset content-type in response. Asset content types are: + text/javascript + application/x-javascript + application/javascript + text/css + image/* + font/* + application/font-* + ~h rex Header line in either request or response + ~hq rex Header in request + ~hs rex Header in response + + ~b rex Expression in the body of either request or response + ~bq rex Expression in the body of request + ~bs rex Expression in the body of response + ~t rex Shortcut for content-type header. + + ~d rex Request domain + ~m rex Method + ~u rex URL + ~c CODE Response code. + rex Equivalent to ~u rex """ + import functools import re import sys @@ -402,6 +403,7 @@ class FUrl(_Rex): code = "u" help = "URL" is_binary = False + flags = re.IGNORECASE # FUrl is special, because it can be "naked". @@ -642,8 +644,7 @@ def _make(): class TFilter(Protocol): pattern: str - def __call__(self, f: flow.Flow) -> bool: - ... # pragma: no cover + def __call__(self, f: flow.Flow) -> bool: ... # pragma: no cover def parse(s: str) -> TFilter: diff --git a/mitmproxy/http.py b/mitmproxy/http.py index 986e6b8983..a6c35b3f65 100644 --- a/mitmproxy/http.py +++ b/mitmproxy/http.py @@ -1,7 +1,6 @@ import binascii import json import os -import re import time import urllib.parse import warnings @@ -27,6 +26,7 @@ from mitmproxy.net.http import status_codes from mitmproxy.net.http import url from mitmproxy.net.http.headers import assemble_content_type +from mitmproxy.net.http.headers import infer_content_encoding from mitmproxy.net.http.headers import parse_content_type from mitmproxy.utils import human from mitmproxy.utils import strutils @@ -402,45 +402,11 @@ def get_content(self, strict: bool = True) -> bytes | None: else: return self.raw_content - def _get_content_type_charset(self) -> str | None: - ct = parse_content_type(self.headers.get("content-type", "")) - if ct: - return ct[2].get("charset") - return None - - def _guess_encoding(self, content: bytes = b"") -> str: - enc = self._get_content_type_charset() - if not enc: - if "json" in self.headers.get("content-type", ""): - enc = "utf8" - if not enc: - if "html" in self.headers.get("content-type", ""): - meta_charset = re.search( - rb"""]+charset=['"]?([^'">]+)""", content, re.IGNORECASE - ) - if meta_charset: - enc = meta_charset.group(1).decode("ascii", "ignore") - if not enc: - if "text/css" in self.headers.get("content-type", ""): - # @charset rule must be the very first thing. - css_charset = re.match( - rb"""@charset "([^"]+)";""", content, re.IGNORECASE - ) - if css_charset: - enc = css_charset.group(1).decode("ascii", "ignore") - if not enc: - enc = "latin-1" - # Use GB 18030 as the superset of GB2312 and GBK to fix common encoding problems on Chinese websites. - if enc.lower() in ("gb2312", "gbk"): - enc = "gb18030" - - return enc - def set_text(self, text: str | None) -> None: if text is None: self.content = None return - enc = self._guess_encoding() + enc = infer_content_encoding(self.headers.get("content-type", "")) try: self.content = cast(bytes, encoding.encode(text, enc)) @@ -464,7 +430,7 @@ def get_text(self, strict: bool = True) -> str | None: content = self.get_content(strict) if content is None: return None - enc = self._guess_encoding(content) + enc = infer_content_encoding(self.headers.get("content-type", ""), content) try: return cast(str, encoding.decode(content, enc)) except ValueError: @@ -1013,9 +979,9 @@ def _set_multipart_form(self, value: list[tuple[bytes, bytes]]) -> None: on generating the boundary. """ boundary = "-" * 20 + binascii.hexlify(os.urandom(16)).decode() - self.headers["content-type"] = ( - ct - ) = f"multipart/form-data; boundary={boundary}" + self.headers["content-type"] = ct = ( + f"multipart/form-data; boundary={boundary}" + ) self.content = multipart.encode_multipart(ct, value) @property diff --git a/mitmproxy/io/compat.py b/mitmproxy/io/compat.py index fe9c4a5972..d4e22ad26a 100644 --- a/mitmproxy/io/compat.py +++ b/mitmproxy/io/compat.py @@ -5,6 +5,7 @@ v3.0.0dev) and versioning. Every change or migration gets a new flow file version number, this prevents issues with developer builds and snapshots. """ + import copy import uuid from typing import Any @@ -423,6 +424,15 @@ def convert_19_20(data): return data +def convert_20_21(data): + data["version"] = 21 + if data["client_conn"]["tls_version"] == "QUIC": + data["client_conn"]["tls_version"] = "QUICv1" + if data["server_conn"]["tls_version"] == "QUIC": + data["server_conn"]["tls_version"] = "QUICv1" + return data + + def _convert_dict_keys(o: Any) -> Any: if isinstance(o, dict): return {strutils.always_str(k): _convert_dict_keys(v) for k, v in o.items()} @@ -487,6 +497,7 @@ def convert_unicode(data: dict) -> dict: 17: convert_17_18, 18: convert_18_19, 19: convert_19_20, + 20: convert_20_21, } diff --git a/mitmproxy/io/har.py b/mitmproxy/io/har.py index cf2dc0ce3a..80f4e933e3 100644 --- a/mitmproxy/io/har.py +++ b/mitmproxy/io/har.py @@ -1,4 +1,5 @@ """Reads HAR files into flow objects""" + import base64 import logging import time @@ -7,12 +8,13 @@ from mitmproxy import connection from mitmproxy import exceptions from mitmproxy import http +from mitmproxy.net.http.headers import infer_content_encoding logger = logging.getLogger(__name__) def fix_headers( - request_headers: list[dict[str, str]] | list[tuple[str, str]] + request_headers: list[dict[str, str]] | list[tuple[str, str]], ) -> http.Headers: """Converts provided headers into (b"header-name", b"header-value") tuples""" flow_headers: list[tuple[bytes, bytes]] = [] @@ -43,7 +45,7 @@ def request_to_flow(request_json: dict) -> http.HTTPFlow: timestamp_start = datetime.fromisoformat( request_json["startedDateTime"].replace("Z", "+00:00") ).timestamp() - timestamp_end = timestamp_start + request_json["time"] + timestamp_end = timestamp_start + request_json["time"] / 1000.0 request_method = request_json["request"]["method"] request_url = request_json["request"]["url"] server_address = request_json.get("serverIPAddress", None) @@ -85,24 +87,52 @@ def request_to_flow(request_json: dict) -> http.HTTPFlow: # In Firefox HAR files images don't include response bodies response_content = request_json["response"]["content"].get("text", "") content_encoding = request_json["response"]["content"].get("encoding", None) + response_headers = fix_headers(request_json["response"]["headers"]) + if content_encoding == "base64": response_content = base64.b64decode(response_content) - response_headers = fix_headers(request_json["response"]["headers"]) + elif isinstance(response_content, str): + # Convert text to bytes, as in `Response.set_text` + try: + response_content = http.encoding.encode( + response_content, + ( + content_encoding + or infer_content_encoding(response_headers.get("content-type", "")) + ), + ) + except ValueError: + # Fallback to UTF-8 + response_content = response_content.encode( + "utf-8", errors="surrogateescape" + ) + + # Then encode the content, as in `Response.set_content` + response_content = http.encoding.encode( + response_content, response_headers.get("content-encoding") or "identity" + ) - new_flow.response = http.Response.make( - response_code, response_content, response_headers + new_flow.response = http.Response( + b"HTTP/1.1", + response_code, + http.status_codes.RESPONSES.get(response_code, "").encode(), + response_headers, + response_content, + None, + timestamp_start, + timestamp_end, ) - # Change time to match HAR file + # Update timestamps + new_flow.request.timestamp_start = timestamp_start new_flow.request.timestamp_end = timestamp_end - new_flow.response.timestamp_start = timestamp_start - new_flow.response.timestamp_end = timestamp_end - new_flow.client_conn.timestamp_start = timestamp_start new_flow.client_conn.timestamp_end = timestamp_end + # Update HTTP version + match http_version_req: case "http/2.0": new_flow.request.http_version = "HTTP/2" diff --git a/mitmproxy/io/io.py b/mitmproxy/io/io.py index e3dd640e46..a388aa2c60 100644 --- a/mitmproxy/io/io.py +++ b/mitmproxy/io/io.py @@ -45,6 +45,10 @@ def stream(self) -> Iterable[flow.Flow]: Yields Flow objects from the dump. """ + if self.peek(4).startswith( + b"\xef\xbb\xbf{" + ): # skip BOM, usually added by Fiddler + self.fo.read(3) if self.peek(1).startswith(b"{"): try: har_file = json.loads(self.fo.read().decode("utf-8")) diff --git a/mitmproxy/io/tnetstring.py b/mitmproxy/io/tnetstring.py index db071eac8c..e5d62a47d9 100644 --- a/mitmproxy/io/tnetstring.py +++ b/mitmproxy/io/tnetstring.py @@ -39,6 +39,7 @@ :License: MIT """ + import collections from typing import BinaryIO from typing import Union @@ -153,7 +154,7 @@ def loads(string: bytes) -> TSerializable: """ This function parses a tnetstring into a python object. """ - return pop(string)[0] + return pop(memoryview(string))[0] def load(file_handle: BinaryIO) -> TSerializable: @@ -177,17 +178,17 @@ def load(file_handle: BinaryIO) -> TSerializable: if c != b":": raise ValueError("not a tnetstring: missing or invalid length prefix") - data = file_handle.read(int(data_length)) + data = memoryview(file_handle.read(int(data_length))) data_type = file_handle.read(1)[0] return parse(data_type, data) -def parse(data_type: int, data: bytes) -> TSerializable: +def parse(data_type: int, data: memoryview) -> TSerializable: if data_type == ord(b","): - return data + return data.tobytes() if data_type == ord(b";"): - return data.decode("utf8") + return str(data, "utf8") if data_type == ord(b"#"): try: return int(data) @@ -225,20 +226,28 @@ def parse(data_type: int, data: bytes) -> TSerializable: raise ValueError(f"unknown type tag: {data_type}") -def pop(data: bytes) -> tuple[TSerializable, bytes]: +def split(data: memoryview, sep: bytes) -> tuple[int, memoryview]: + i = 0 + try: + ord_sep = ord(sep) + while data[i] != ord_sep: + i += 1 + # here i is the position of b":" in the memoryview + return int(data[:i]), data[i + 1 :] + except (IndexError, ValueError): + raise ValueError( + f"not a tnetstring: missing or invalid length prefix: {data.tobytes()!r}" + ) + + +def pop(data: memoryview) -> tuple[TSerializable, memoryview]: """ This function parses a tnetstring into a python object. It returns a tuple giving the parsed object and a string containing any unparsed data from the end of the string. """ - # Parse out data length, type and remaining string. - try: - blength, data = data.split(b":", 1) - length = int(blength) - except ValueError: - raise ValueError( - f"not a tnetstring: missing or invalid length prefix: {data!r}" - ) + # Parse out data length, type and remaining string. + length, data = split(data, b":") try: data, data_type, remain = data[:length], data[length], data[length + 1 :] except IndexError: diff --git a/mitmproxy/master.py b/mitmproxy/master.py index aa92df9749..7ed6fde5c9 100644 --- a/mitmproxy/master.py +++ b/mitmproxy/master.py @@ -4,6 +4,7 @@ from . import ctx as mitmproxy_ctx from .addons import termlog from .proxy.mode_specs import ReverseMode +from .utils import asyncio_utils from mitmproxy import addonmanager from mitmproxy import command from mitmproxy import eventsequence @@ -51,11 +52,13 @@ def __init__( mitmproxy_ctx.options = self.options async def run(self) -> None: - old_handler = self.event_loop.get_exception_handler() - self.event_loop.set_exception_handler(self._asyncio_exception_handler) - try: + with ( + asyncio_utils.install_exception_handler(self._asyncio_exception_handler), + asyncio_utils.set_eager_task_factory(), + ): self.should_exit.clear() + # Can we exit before even bringing up servers? if ec := self.addons.get("errorcheck"): await ec.shutdown_if_errored() if ps := self.addons.get("proxyserver"): @@ -67,17 +70,24 @@ async def run(self) -> None: ], return_when=asyncio.FIRST_COMPLETED, ) - if ec := self.addons.get("errorcheck"): - await ec.shutdown_if_errored() - ec.finish() - await self.running() + if self.should_exit.is_set(): + return + # Did bringing up servers fail? + if ec := self.addons.get("errorcheck"): + await ec.shutdown_if_errored() + try: + await self.running() + # Any errors in the final part of startup? + if ec := self.addons.get("errorcheck"): + await ec.shutdown_if_errored() + ec.finish() + await self.should_exit.wait() finally: - # .wait might be cancelled (e.g. by sys.exit) + # if running() was called, we also always want to call done(). + # .wait might be cancelled (e.g. by sys.exit), so this needs to be in a finally block. await self.done() - finally: - self.event_loop.set_exception_handler(old_handler) def shutdown(self): """ diff --git a/mitmproxy/net/dns/domain_names.py b/mitmproxy/net/dns/domain_names.py index d99f03c64a..520fb65e15 100644 --- a/mitmproxy/net/dns/domain_names.py +++ b/mitmproxy/net/dns/domain_names.py @@ -1,6 +1,8 @@ import struct from typing import Optional +from . import types + _LABEL_SIZE = struct.Struct("!B") _POINTER_OFFSET = struct.Struct("!H") _POINTER_INDICATOR = 0b11000000 @@ -28,7 +30,7 @@ def _unpack_label_into(labels: list[str], buffer: bytes, offset: int) -> int: labels.append(buffer[offset:end_label].decode("idna")) except UnicodeDecodeError: raise struct.error( - f"unpack encountered a illegal characters at offset {offset}" + f"unpack encountered an illegal characters at offset {offset}" ) return _LABEL_SIZE.size + size @@ -105,3 +107,63 @@ def pack(name: str) -> bytes: buffer.extend(label) buffer.extend(_LABEL_SIZE.pack(0)) return bytes(buffer) + + +def record_data_can_have_compression(record_type: int) -> bool: + if record_type in ( + types.CNAME, + types.HINFO, + types.MB, + types.MD, + types.MF, + types.MG, + types.MINFO, + types.MR, + types.MX, + types.NS, + types.PTR, + types.SOA, + types.TXT, + types.RP, + types.AFSDB, + types.RT, + types.SIG, + types.PX, + types.NXT, + types.NAPTR, + types.SRV, + ): + return True + return False + + +def decompress_from_record_data( + buffer: bytes, offset: int, end_data: int, cached_names: Cache +) -> bytes: + # we decompress compression pointers in RDATA by iterating through each byte and checking + # if it has a leading 0b11, if so we try to decompress it and update it in the data variable. + data = bytearray(buffer[offset:end_data]) + data_offset = 0 + decompress_size = 0 + while data_offset < end_data - offset: + if buffer[offset + data_offset] & _POINTER_INDICATOR == _POINTER_INDICATOR: + try: + ( + rr_name, + rr_name_len, + ) = unpack_from_with_compression( + buffer, offset + data_offset, cached_names + ) + data[ + data_offset + decompress_size : data_offset + + decompress_size + + rr_name_len + ] = pack(rr_name) + decompress_size += len(rr_name) + data_offset += rr_name_len + continue + except struct.error: + # the byte isn't actually a domain name compression pointer but some other data type + pass + data_offset += 1 + return bytes(data) diff --git a/mitmproxy/net/dns/https_records.py b/mitmproxy/net/dns/https_records.py new file mode 100644 index 0000000000..165a4235ab --- /dev/null +++ b/mitmproxy/net/dns/https_records.py @@ -0,0 +1,108 @@ +import enum +import struct +from dataclasses import dataclass + +from . import domain_names + +""" +HTTPS records are formatted as follows (as per RFC9460): +- a 2-octet field for SvcPriority as an integer in network byte order. +- the uncompressed, fully qualified TargetName, represented as a sequence of length-prefixed labels per Section 3.1 of [RFC1035]. +- the SvcParams, consuming the remainder of the record (so smaller than 65535 octets and constrained by the RDATA and DNS message sizes). + +When the list of SvcParams is non-empty, it contains a series of SvcParamKey=SvcParamValue pairs, represented as: +- a 2-octet field containing the SvcParamKey as an integer in network byte order. (See Section 14.3.2 for the defined values.) +- a 2-octet field containing the length of the SvcParamValue as an integer between 0 and 65535 in network byte order. +- an octet string of this length whose contents are the SvcParamValue in a format determined by the SvcParamKey. + + https://datatracker.ietf.org/doc/rfc9460/ + https://datatracker.ietf.org/doc/rfc1035/ +""" + + +class SVCParamKeys(enum.Enum): + MANDATORY = 0 + ALPN = 1 + NO_DEFAULT_ALPN = 2 + PORT = 3 + IPV4HINT = 4 + ECH = 5 + IPV6HINT = 6 + + +@dataclass +class HTTPSRecord: + priority: int + target_name: str + params: dict[int, bytes] + + def __repr__(self): + params = {} + for param_type, param_value in self.params.items(): + try: + name = SVCParamKeys(param_type).name.lower() + except ValueError: + name = f"key{param_type}" + params[name] = param_value + return f"priority: {self.priority} target_name: '{self.target_name}' {params}" + + +def _unpack_params(data: bytes, offset: int) -> dict[int, bytes]: + """Unpacks the service parameters from the given offset.""" + params = {} + while offset < len(data): + param_type = struct.unpack("!H", data[offset : offset + 2])[0] + offset += 2 + param_length = struct.unpack("!H", data[offset : offset + 2])[0] + offset += 2 + if offset + param_length > len(data): + raise struct.error( + "unpack requires a buffer of %i bytes" % (offset + param_length) + ) + param_value = data[offset : offset + param_length] + offset += param_length + params[param_type] = param_value + return params + + +def unpack(data: bytes) -> HTTPSRecord: + """ + Unpacks HTTPS RDATA from byte data. + + Raises: + struct.error if the record is malformed. + """ + offset = 0 + + # Priority (2 bytes) + priority = struct.unpack("!h", data[offset : offset + 2])[0] + offset += 2 + + # TargetName (variable length) + target_name, offset = domain_names.unpack_from(data, offset) + + # Service Parameters (remaining bytes) + params = _unpack_params(data, offset) + + return HTTPSRecord(priority=priority, target_name=target_name, params=params) + + +def _pack_params(params: dict[int, bytes]) -> bytes: + """Converts the service parameters into the raw byte format""" + buffer = bytearray() + + for k, v in params.items(): + buffer.extend(struct.pack("!H", k)) + buffer.extend(struct.pack("!H", len(v))) + buffer.extend(v) + + return bytes(buffer) + + +def pack(record: HTTPSRecord) -> bytes: + """Packs the HTTPS record into its bytes form.""" + buffer = bytearray() + buffer.extend(struct.pack("!h", record.priority)) + buffer.extend(domain_names.pack(record.target_name)) + buffer.extend(_pack_params(record.params)) + return bytes(buffer) diff --git a/mitmproxy/net/encoding.py b/mitmproxy/net/encoding.py index 17a48f1caa..ca4a71ace1 100644 --- a/mitmproxy/net/encoding.py +++ b/mitmproxy/net/encoding.py @@ -1,6 +1,7 @@ """ Utility functions for decoding response bodies. """ + import codecs import collections import gzip @@ -20,18 +21,15 @@ @overload -def decode(encoded: None, encoding: str, errors: str = "strict") -> None: - ... +def decode(encoded: None, encoding: str, errors: str = "strict") -> None: ... @overload -def decode(encoded: str, encoding: str, errors: str = "strict") -> str: - ... +def decode(encoded: str, encoding: str, errors: str = "strict") -> str: ... @overload -def decode(encoded: bytes, encoding: str, errors: str = "strict") -> str | bytes: - ... +def decode(encoded: bytes, encoding: str, errors: str = "strict") -> str | bytes: ... def decode( @@ -81,18 +79,15 @@ def decode( @overload -def encode(decoded: None, encoding: str, errors: str = "strict") -> None: - ... +def encode(decoded: None, encoding: str, errors: str = "strict") -> None: ... @overload -def encode(decoded: str, encoding: str, errors: str = "strict") -> str | bytes: - ... +def encode(decoded: str, encoding: str, errors: str = "strict") -> str | bytes: ... @overload -def encode(decoded: bytes, encoding: str, errors: str = "strict") -> bytes: - ... +def encode(decoded: bytes, encoding: str, errors: str = "strict") -> bytes: ... def encode( @@ -152,16 +147,15 @@ def identity(content): def decode_gzip(content: bytes) -> bytes: if not content: return b"" - gfile = gzip.GzipFile(fileobj=BytesIO(content)) - return gfile.read() + with gzip.GzipFile(fileobj=BytesIO(content)) as f: + return f.read() def encode_gzip(content: bytes) -> bytes: s = BytesIO() # set mtime to 0 so that gzip encoding is deterministic. - gf = gzip.GzipFile(fileobj=s, mode="wb", mtime=0) - gf.write(content) - gf.close() + with gzip.GzipFile(fileobj=s, mode="wb", mtime=0) as f: + f.write(content) return s.getvalue() @@ -179,12 +173,7 @@ def decode_zstd(content: bytes) -> bytes: if not content: return b"" zstd_ctx = zstd.ZstdDecompressor() - try: - return zstd_ctx.decompress(content) - except zstd.ZstdError: - # If the zstd stream is streamed without a size header, - # try decoding with a 10MiB output buffer - return zstd_ctx.decompress(content, max_output_size=10 * 2**20) + return zstd_ctx.stream_reader(BytesIO(content), read_across_frames=True).read() def encode_zstd(content: bytes) -> bytes: diff --git a/mitmproxy/net/http/headers.py b/mitmproxy/net/http/headers.py index e87efc5032..7e14b2a77c 100644 --- a/mitmproxy/net/http/headers.py +++ b/mitmproxy/net/http/headers.py @@ -1,4 +1,5 @@ import collections +import re def parse_content_type(c: str) -> tuple[str, str, dict[str, str]] | None: @@ -33,3 +34,39 @@ def assemble_content_type(type, subtype, parameters): return f"{type}/{subtype}" params = "; ".join(f"{k}={v}" for k, v in parameters.items()) return f"{type}/{subtype}; {params}" + + +def infer_content_encoding(content_type: str, content: bytes = b"") -> str: + """ + Infer the encoding of content from the content-type header. + """ + # Use the charset from the header if possible + parsed_content_type = parse_content_type(content_type) + enc = parsed_content_type[2].get("charset") if parsed_content_type else None + + # Otherwise, infer the encoding + if not enc and "json" in content_type: + enc = "utf8" + + if not enc and "html" in content_type: + meta_charset = re.search( + rb"""]+charset=['"]?([^'">]+)""", content, re.IGNORECASE + ) + if meta_charset: + enc = meta_charset.group(1).decode("ascii", "ignore") + + if not enc and "text/css" in content_type: + # @charset rule must be the very first thing. + css_charset = re.match(rb"""@charset "([^"]+)";""", content, re.IGNORECASE) + if css_charset: + enc = css_charset.group(1).decode("ascii", "ignore") + + # Fallback to latin-1 + if not enc: + enc = "latin-1" + + # Use GB 18030 as the superset of GB2312 and GBK to fix common encoding problems on Chinese websites. + if enc.lower() in ("gb2312", "gbk"): + enc = "gb18030" + + return enc diff --git a/mitmproxy/net/http/user_agents.py b/mitmproxy/net/http/user_agents.py index 6a83f8fb79..65b8d0cfe4 100644 --- a/mitmproxy/net/http/user_agents.py +++ b/mitmproxy/net/http/user_agents.py @@ -1,6 +1,6 @@ """ - A small collection of useful user-agent header strings. These should be - kept reasonably current to reflect common usage. +A small collection of useful user-agent header strings. These should be +kept reasonably current to reflect common usage. """ # pylint: line-too-long # A collection of (name, shortcut, string) tuples. diff --git a/mitmproxy/net/local_ip.py b/mitmproxy/net/local_ip.py index bc3087263c..919d31dd33 100644 --- a/mitmproxy/net/local_ip.py +++ b/mitmproxy/net/local_ip.py @@ -10,14 +10,16 @@ def get_local_ip(reachable: str = "8.8.8.8") -> str | None: We use Google DNS's IPv4 address as the default. """ # https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s = None try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect((reachable, 80)) - return s.getsockname()[0] + return s.getsockname()[0] # pragma: no cover except OSError: - return None + return None # pragma: no cover finally: - s.close() + if s is not None: + s.close() def get_local_ip6(reachable: str = "2001:4860:4860::8888") -> str | None: @@ -26,11 +28,13 @@ def get_local_ip6(reachable: str = "2001:4860:4860::8888") -> str | None: This will fail if the target address is known to be unreachable. We use Google DNS's IPv6 address as the default. """ - s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + s = None try: + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s.connect((reachable, 80)) - return s.getsockname()[0] + return s.getsockname()[0] # pragma: no cover except OSError: - return None + return None # pragma: no cover finally: - s.close() + if s is not None: + s.close() diff --git a/mitmproxy/net/server_spec.py b/mitmproxy/net/server_spec.py index f0d5edd609..254811ff3f 100644 --- a/mitmproxy/net/server_spec.py +++ b/mitmproxy/net/server_spec.py @@ -1,6 +1,7 @@ """ Server specs are used to describe an upstream proxy or server. """ + import re from functools import cache from typing import Literal diff --git a/mitmproxy/net/tls.py b/mitmproxy/net/tls.py index 21b4754a48..e844dc1419 100644 --- a/mitmproxy/net/tls.py +++ b/mitmproxy/net/tls.py @@ -3,6 +3,7 @@ from collections.abc import Callable from collections.abc import Iterable from enum import Enum +from functools import cache from functools import lru_cache from pathlib import Path from typing import Any @@ -58,6 +59,22 @@ class Verify(Enum): DEFAULT_OPTIONS = SSL.OP_CIPHER_SERVER_PREFERENCE | SSL.OP_NO_COMPRESSION +@cache +def is_supported_version(version: Version): + client_ctx = SSL.Context(SSL.TLS_CLIENT_METHOD) + client_ctx.set_min_proto_version(version.value) + client_ctx.set_max_proto_version(version.value) + client_conn = SSL.Connection(client_ctx) + client_conn.set_connect_state() + + try: + client_conn.recv(4096) + except SSL.WantReadError: + return True + except SSL.Error: + return False + + class MasterSecretLogger: def __init__(self, filename: Path): self.filename = filename.expanduser() diff --git a/mitmproxy/net/udp.py b/mitmproxy/net/udp.py deleted file mode 100644 index 37892c997f..0000000000 --- a/mitmproxy/net/udp.py +++ /dev/null @@ -1,279 +0,0 @@ -from __future__ import annotations - -import asyncio -import logging -import socket -from collections.abc import Callable -from typing import Any -from typing import cast -from typing import Union - -import mitmproxy_rs - -from mitmproxy.connection import Address -from mitmproxy.utils import human - -logger = logging.getLogger(__name__) - -MAX_DATAGRAM_SIZE = 65535 - 20 - -DatagramReceivedCallback = Callable[ - [asyncio.DatagramTransport, bytes, Address, Address], None -] -""" -Callable that gets invoked when a datagram is received. -The first argument is the outgoing transport. -The second argument is the received payload. -The third argument is the source address, also referred to as `remote_addr` or `peername`. -The fourth argument is the destination address, also referred to as `local_addr` or `sockname`. -""" - -# to make mypy happy -SockAddress = Union[tuple[str, int], tuple[str, int, int, int]] - - -class DrainableDatagramProtocol(asyncio.DatagramProtocol): - _loop: asyncio.AbstractEventLoop - _closed: asyncio.Event - _paused: int - _can_write: asyncio.Event - _sock: socket.socket | None - - def __init__(self, loop: asyncio.AbstractEventLoop | None) -> None: - self._loop = asyncio.get_running_loop() if loop is None else loop - self._closed = asyncio.Event() - self._paused = 0 - self._can_write = asyncio.Event() - self._can_write.set() - self._sock = None - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} socket={self._sock!r}>" - - @property - def sockets(self) -> tuple[socket.socket, ...]: - return () if self._sock is None else (self._sock,) - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - self._sock = transport.get_extra_info("socket") - - def connection_lost(self, exc: Exception | None) -> None: - self._closed.set() - if exc: - logger.warning(f"Connection lost on {self!r}: {exc!r}") # pragma: no cover - - def pause_writing(self) -> None: - self._paused = self._paused + 1 - if self._paused == 1: - self._can_write.clear() - - def resume_writing(self) -> None: - assert self._paused > 0 - self._paused = self._paused - 1 - if self._paused == 0: - self._can_write.set() - - async def drain(self) -> None: - await self._can_write.wait() - - def error_received(self, exc: Exception) -> None: - logger.warning(f"Send/receive on {self!r} failed: {exc!r}") # pragma: no cover - - async def wait_closed(self) -> None: - await self._closed.wait() - - -class UdpServer(DrainableDatagramProtocol): - """UDP server similar to base_events.Server""" - - # _datagram_received_cb: DatagramReceivedCallback - _transport: asyncio.DatagramTransport | None - _local_addr: Address | None - - def __init__( - self, - datagram_received_cb: DatagramReceivedCallback, - loop: asyncio.AbstractEventLoop | None, - ) -> None: - super().__init__(loop) - self._datagram_received_cb = datagram_received_cb - self._transport = None - self._local_addr = None - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - if self._transport is None: - self._transport = cast(asyncio.DatagramTransport, transport) - self._transport.set_protocol(self) - self._local_addr = transport.get_extra_info("sockname") - super().connection_made(transport) - - def datagram_received(self, data: bytes, addr: Any) -> None: - assert self._transport is not None - assert self._local_addr is not None - self._datagram_received_cb(self._transport, data, addr, self._local_addr) - - def close(self) -> None: - if self._transport is not None: - self._transport.close() - - -class DatagramReader: - _packets: asyncio.Queue[bytes] - _eof: bool - - def __init__(self) -> None: - self._packets = asyncio.Queue(42) # ~2.75MB - self._eof = False - - def feed_data(self, data: bytes, remote_addr: Address) -> None: - assert len(data) <= MAX_DATAGRAM_SIZE - if self._eof: - logger.info( - f"Received UDP packet from {human.format_address(remote_addr)} after EOF." - ) - else: - try: - self._packets.put_nowait(data) - except asyncio.QueueFull: - logger.debug( - f"Dropped UDP packet from {human.format_address(remote_addr)}." - ) - - def feed_eof(self) -> None: - self._eof = True - try: - self._packets.put_nowait(b"") - except asyncio.QueueFull: - pass - - async def read(self, n: int) -> bytes: - assert n >= MAX_DATAGRAM_SIZE - if self._eof: - try: - return self._packets.get_nowait() - except asyncio.QueueEmpty: - return b"" - else: - try: - return await self._packets.get() - except RuntimeError: # pragma: no cover - # event loop got closed - return b"" - - -class DatagramWriter: - _transport: asyncio.DatagramTransport | mitmproxy_rs.DatagramTransport - _remote_addr: Address - _reader: DatagramReader | None - _closed: asyncio.Event | None - - def __init__( - self, - transport: asyncio.DatagramTransport | mitmproxy_rs.DatagramTransport, - remote_addr: Address, - reader: DatagramReader | None = None, - ) -> None: - """ - Create a new datagram writer around the given transport. - Specify a reader to prevent closing the transport and instead only feed EOF to the reader. - """ - self._transport = transport - self._remote_addr = remote_addr - if reader is not None: - self._reader = reader - self._closed = asyncio.Event() - else: - self._reader = None - self._closed = None - - @property - def _protocol( - self, - ) -> DrainableDatagramProtocol | mitmproxy_rs.DatagramTransport: - return self._transport.get_protocol() # type: ignore - - def write(self, data: bytes) -> None: - self._transport.sendto(data, self._remote_addr) - - def write_eof(self) -> None: - raise OSError("UDP does not support half-closing.") - - def get_extra_info(self, name: str, default: Any = None) -> Any: - if name == "peername": - return self._remote_addr - else: - return self._transport.get_extra_info(name, default) - - def close(self) -> None: - if self._closed is None: - self._transport.close() - else: - self._closed.set() - assert self._reader - self._reader.feed_eof() - - def is_closing(self) -> bool: - if self._closed is None: - return self._transport.is_closing() - else: - return self._closed.is_set() - - async def wait_closed(self) -> None: - if self._closed is None: - await self._protocol.wait_closed() - else: - await self._closed.wait() - - async def drain(self) -> None: - await self._protocol.drain() - - -class UdpClient(DrainableDatagramProtocol): - """UDP protocol for upstream connections.""" - - _reader: DatagramReader - - def __init__(self, reader: DatagramReader, loop: asyncio.AbstractEventLoop | None): - super().__init__(loop) - self._reader = reader - - def datagram_received(self, data: bytes, remote_addr: Address) -> None: - self._reader.feed_data(data, remote_addr) - - def connection_lost(self, exc: Exception | None) -> None: - self._reader.feed_eof() - super().connection_lost(exc) - - -async def start_server( - datagram_received_cb: DatagramReceivedCallback, - host: str, - port: int, -) -> UdpServer: - """UDP variant of asyncio.start_server.""" - - assert host, "Cannot bind to an empty host for UDP sockets on Windows or Ubuntu." - loop = asyncio.get_running_loop() - _, protocol = await loop.create_datagram_endpoint( - lambda: UdpServer(datagram_received_cb, loop), - local_addr=(host, port), - ) - assert isinstance(protocol, UdpServer) - return protocol - - -async def open_connection( - host: str, port: int, *, local_addr: Address | None = None -) -> tuple[DatagramReader, DatagramWriter]: - """UDP variant of asyncio.open_connection.""" - - loop = asyncio.get_running_loop() - reader = DatagramReader() - transport, _ = await loop.create_datagram_endpoint( - lambda: UdpClient(reader, loop), local_addr=local_addr, remote_addr=(host, port) - ) - writer = DatagramWriter( - cast(asyncio.DatagramTransport, transport), - remote_addr=transport.get_extra_info("peername"), - ) - return reader, writer diff --git a/mitmproxy/options.py b/mitmproxy/options.py index 6ef97db44a..4f0c0d5253 100644 --- a/mitmproxy/options.py +++ b/mitmproxy/options.py @@ -21,6 +21,16 @@ def __init__(self, **kwargs) -> None: False, "Use the Host header to construct URLs for display.", ) + self.add_option( + "show_ignored_hosts", + bool, + False, + """ + Record ignored flows in the UI even if we do not perform TLS interception. + This option will keep ignored flows' contents in memory, which can greatly increase memory usage. + A future release will fix this issue, record ignored flows by default, and remove this option. + """, + ) # Proxy options self.add_option( @@ -149,6 +159,12 @@ def __init__(self, **kwargs) -> None: True, "Enable/disable support for QUIC and HTTP/3. Enabled by default.", ) + self.add_option( + "http_connect_send_host_header", + bool, + True, + "Include host header with CONNECT requests. Enabled by default.", + ) self.add_option( "websocket", bool, diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py index b116f31d13..c77b3945fe 100644 --- a/mitmproxy/optmanager.py +++ b/mitmproxy/optmanager.py @@ -267,7 +267,7 @@ def toggler(self, attr): if attr not in self._options: raise KeyError("No such option: %s" % attr) o = self._options[attr] - if o.typespec != bool: + if o.typespec is not bool: raise ValueError("Toggler can only be used with boolean options") def toggle(): @@ -379,7 +379,7 @@ def _parse_setval(self, o: _Option, values: list[str]) -> Any: optstr = None if o.typespec in (str, Optional[str]): - if o.typespec == str and optstr is None: + if o.typespec is str and optstr is None: raise exceptions.OptionsError(f"Option is required: {o.name}") return optstr elif o.typespec in (int, Optional[int]): @@ -388,11 +388,11 @@ def _parse_setval(self, o: _Option, values: list[str]) -> Any: return int(optstr) except ValueError: raise exceptions.OptionsError(f"Not an integer: {optstr}") - elif o.typespec == int: + elif o.typespec is int: raise exceptions.OptionsError(f"Option is required: {o.name}") else: return None - elif o.typespec == bool: + elif o.typespec is bool: if optstr == "toggle": return not o.current() if not optstr or optstr == "true": @@ -424,7 +424,7 @@ def mkf(x, s): flags = mkf(optname, short) - if o.typespec == bool: + if o.typespec is bool: g = parser.add_mutually_exclusive_group(required=False) onf = mkf(optname, None) offf = mkf("no-" + optname, None) @@ -523,7 +523,7 @@ def parse(text): if not text: return {} try: - yaml = ruamel.yaml.YAML(typ="unsafe", pure=True) + yaml = ruamel.yaml.YAML(typ="safe", pure=True) data = yaml.load(text) except ruamel.yaml.error.YAMLError as v: if hasattr(v, "problem_mark"): diff --git a/mitmproxy/platform/windows.py b/mitmproxy/platform/windows.py index 53539d4b77..a42f649e1c 100644 --- a/mitmproxy/platform/windows.py +++ b/mitmproxy/platform/windows.py @@ -4,6 +4,7 @@ import contextlib import ctypes.wintypes import json +import logging import os import re import socket @@ -25,6 +26,9 @@ REDIRECT_API_PORT = 8085 +logger = logging.getLogger(__name__) + + ########################## # Resolver @@ -460,6 +464,9 @@ def __init__( def setup(cls): # TODO: Make sure that server can be killed cleanly. That's a bit difficult as we don't have access to # controller.should_exit when this is called. + logger.warning( + "Transparent mode on Windows is unsupported and flaky. Consider using local redirect mode or WireGuard mode instead." + ) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_unavailable = s.connect_ex((REDIRECT_API_HOST, REDIRECT_API_PORT)) if server_unavailable: diff --git a/mitmproxy/proxy/commands.py b/mitmproxy/proxy/commands.py index e6749dccda..17e09248f7 100644 --- a/mitmproxy/proxy/commands.py +++ b/mitmproxy/proxy/commands.py @@ -6,6 +6,7 @@ The counterpart to commands are events. """ + import logging import warnings from typing import TYPE_CHECKING diff --git a/mitmproxy/proxy/events.py b/mitmproxy/proxy/events.py index c0518631c7..0ed3e3cb7d 100644 --- a/mitmproxy/proxy/events.py +++ b/mitmproxy/proxy/events.py @@ -3,6 +3,7 @@ Events represent the only way for layers to receive new data from sockets. The counterpart to events are commands. """ + import typing import warnings from dataclasses import dataclass diff --git a/mitmproxy/proxy/layer.py b/mitmproxy/proxy/layer.py index 27328c4fc7..14180fff38 100644 --- a/mitmproxy/proxy/layer.py +++ b/mitmproxy/proxy/layer.py @@ -1,6 +1,7 @@ """ Base class for protocol layers. """ + import collections import textwrap from abc import abstractmethod @@ -27,7 +28,7 @@ """ -MAX_LOG_STATEMENT_SIZE = 512 +MAX_LOG_STATEMENT_SIZE = 2048 """Maximum size of individual log statements before they will be truncated.""" diff --git a/mitmproxy/proxy/layers/dns.py b/mitmproxy/proxy/layers/dns.py index e2e5c701bb..238b0feff1 100644 --- a/mitmproxy/proxy/layers/dns.py +++ b/mitmproxy/proxy/layers/dns.py @@ -1,14 +1,19 @@ import struct from dataclasses import dataclass +from typing import List +from typing import Literal from mitmproxy import dns from mitmproxy import flow as mflow +from mitmproxy.net.dns import response_codes from mitmproxy.proxy import commands from mitmproxy.proxy import events from mitmproxy.proxy import layer from mitmproxy.proxy.context import Context from mitmproxy.proxy.utils import expect +_LENGTH_LABEL = struct.Struct("!H") + @dataclass class DnsRequestHook(commands.StartHook): @@ -37,16 +42,30 @@ class DnsErrorHook(commands.StartHook): flow: dns.DNSFlow +def pack_message( + message: dns.Message, transport_protocol: Literal["tcp", "udp"] +) -> bytes: + packed = message.packed + if transport_protocol == "tcp": + return struct.pack("!H", len(packed)) + packed + else: + return packed + + class DNSLayer(layer.Layer): """ Layer that handles resolving DNS queries. """ flows: dict[int, dns.DNSFlow] + req_buf: bytearray + resp_buf: bytearray def __init__(self, context: Context): super().__init__(context) self.flows = {} + self.req_buf = bytearray() + self.resp_buf = bytearray() def handle_request( self, flow: dns.DNSFlow, msg: dns.Message @@ -55,6 +74,8 @@ def handle_request( yield DnsRequestHook(flow) if flow.response: yield from self.handle_response(flow, flow.response) + elif flow.error: + yield from self.handle_error(flow, flow.error.msg) elif not self.context.server.address: yield from self.handle_error( flow, "No hook has set a response and there is no upstream server." @@ -66,7 +87,8 @@ def handle_request( yield from self.handle_error(flow, str(err)) # cannot recover from this return - yield commands.SendData(self.context.server, flow.request.packed) + packed = pack_message(flow.request, flow.server_conn.transport_protocol) + yield commands.SendData(self.context.server, packed) def handle_response( self, flow: dns.DNSFlow, msg: dns.Message @@ -74,11 +96,48 @@ def handle_response( flow.response = msg yield DnsResponseHook(flow) if flow.response: - yield commands.SendData(self.context.client, flow.response.packed) + packed = pack_message(flow.response, flow.client_conn.transport_protocol) + yield commands.SendData(self.context.client, packed) def handle_error(self, flow: dns.DNSFlow, err: str) -> layer.CommandGenerator[None]: flow.error = mflow.Error(err) yield DnsErrorHook(flow) + servfail = flow.request.fail(response_codes.SERVFAIL) + yield commands.SendData( + self.context.client, + pack_message(servfail, flow.client_conn.transport_protocol), + ) + + def unpack_message(self, data: bytes, from_client: bool) -> List[dns.Message]: + msgs: List[dns.Message] = [] + + buf = self.req_buf if from_client else self.resp_buf + + if self.context.client.transport_protocol == "udp": + msgs.append(dns.Message.unpack(data)) + elif self.context.client.transport_protocol == "tcp": + buf.extend(data) + size = len(buf) + offset = 0 + + while True: + if size - offset < _LENGTH_LABEL.size: + break + (expected_size,) = _LENGTH_LABEL.unpack_from(buf, offset) + offset += _LENGTH_LABEL.size + if expected_size == 0: + raise struct.error("Message length field cannot be zero") + + if size - offset < expected_size: + offset -= _LENGTH_LABEL.size + break + + data = bytes(buf[offset : expected_size + offset]) + offset += expected_size + msgs.append(dns.Message.unpack(data)) + + del buf[:offset] + return msgs @expect(events.Start) def state_start(self, _) -> layer.CommandGenerator[None]: @@ -91,24 +150,26 @@ def state_query(self, event: events.Event) -> layer.CommandGenerator[None]: from_client = event.connection is self.context.client if isinstance(event, events.DataReceived): + msgs: List[dns.Message] = [] try: - msg = dns.Message.unpack(event.data) + msgs = self.unpack_message(event.data, from_client) except struct.error as e: yield commands.Log(f"{event.connection} sent an invalid message: {e}") yield commands.CloseConnection(event.connection) self._handle_event = self.state_done else: - try: - flow = self.flows[msg.id] - except KeyError: - flow = dns.DNSFlow( - self.context.client, self.context.server, live=True - ) - self.flows[msg.id] = flow - if from_client: - yield from self.handle_request(flow, msg) - else: - yield from self.handle_response(flow, msg) + for msg in msgs: + try: + flow = self.flows[msg.id] + except KeyError: + flow = dns.DNSFlow( + self.context.client, self.context.server, live=True + ) + self.flows[msg.id] = flow + if from_client: + yield from self.handle_request(flow, msg) + else: + yield from self.handle_response(flow, msg) elif isinstance(event, events.ConnectionClosed): other_conn = self.context.server if from_client else self.context.client diff --git a/mitmproxy/proxy/layers/http/__init__.py b/mitmproxy/proxy/layers/http/__init__.py index 419d2971b3..6bf80b90e0 100644 --- a/mitmproxy/proxy/layers/http/__init__.py +++ b/mitmproxy/proxy/layers/http/__init__.py @@ -27,6 +27,8 @@ from ._events import ResponseHeaders from ._events import ResponseProtocolError from ._events import ResponseTrailers +from ._hooks import HttpConnectedHook +from ._hooks import HttpConnectErrorHook from ._hooks import HttpConnectHook from ._hooks import HttpErrorHook from ._hooks import HttpRequestHeadersHook @@ -59,6 +61,7 @@ from mitmproxy.proxy.layers import websocket from mitmproxy.proxy.layers.http import _upstream_proxy from mitmproxy.proxy.utils import expect +from mitmproxy.proxy.utils import ReceiveBuffer from mitmproxy.utils import human from mitmproxy.websocket import WebSocketData @@ -143,8 +146,8 @@ class DropStream(HttpCommand): class HttpStream(layer.Layer): - request_body_buf: bytes - response_body_buf: bytes + request_body_buf: ReceiveBuffer + response_body_buf: ReceiveBuffer flow: http.HTTPFlow stream_id: StreamId child_layer: layer.Layer | None = None @@ -158,8 +161,8 @@ def mode(self) -> HTTPMode: def __init__(self, context: Context, stream_id: int) -> None: super().__init__(context) - self.request_body_buf = b"" - self.response_body_buf = b"" + self.request_body_buf = ReceiveBuffer() + self.response_body_buf = ReceiveBuffer() self.client_state = self.state_uninitialized self.server_state = self.state_uninitialized self.stream_id = stream_id @@ -275,7 +278,7 @@ def state_wait_for_request_headers( ) self.flow.request.headers.pop("expect") - if self.flow.request.stream: + if self.flow.request.stream and not event.end_stream: yield from self.start_request_stream() else: self.client_state = self.state_consume_request_body @@ -352,8 +355,8 @@ def state_consume_request_body( self.flow.request.trailers = event.trailers elif isinstance(event, RequestEndOfMessage): self.flow.request.timestamp_end = time.time() - self.flow.request.data.content = self.request_body_buf - self.request_body_buf = b"" + self.flow.request.data.content = bytes(self.request_body_buf) + self.request_body_buf.clear() self.client_state = self.state_done yield HttpRequestHook(self.flow) if (yield from self.check_killed(True)): @@ -403,7 +406,7 @@ def state_wait_for_response_headers( if (yield from self.check_killed(True)): return - elif self.flow.response.stream: + elif self.flow.response.stream and not event.end_stream: yield from self.start_response_stream() else: self.server_state = self.state_consume_response_body @@ -459,8 +462,8 @@ def state_consume_response_body( self.flow.response.trailers = event.trailers elif isinstance(event, ResponseEndOfMessage): assert self.flow.response - self.flow.response.data.content = self.response_body_buf - self.response_body_buf = b"" + self.flow.response.data.content = bytes(self.response_body_buf) + self.response_body_buf.clear() yield from self.send_response() def send_response(self, already_streamed: bool = False): @@ -528,8 +531,8 @@ def flow_done(self) -> layer.CommandGenerator[None]: yield commands.Log( f"{self.debug}[http] upgrading to {self.child_layer}", DEBUG ) - yield from self.child_layer.handle_event(events.Start()) self._handle_event = self.passthrough + yield from self.child_layer.handle_event(events.Start()) else: yield DropStream(self.stream_id) @@ -605,16 +608,16 @@ def check_body_size(self, request: bool) -> layer.CommandGenerator[bool]: self.flow.request.stream = True if self.request_body_buf: # clear buffer and then fake a DataReceived event with everything we had in the buffer so far. - body_buf = self.request_body_buf - self.request_body_buf = b"" + body_buf = bytes(self.request_body_buf) + self.request_body_buf.clear() yield from self.start_request_stream() yield from self.handle_event(RequestData(self.stream_id, body_buf)) if response: assert self.flow.response self.flow.response.stream = True if self.response_body_buf: - body_buf = self.response_body_buf - self.response_body_buf = b"" + body_buf = bytes(self.response_body_buf) + self.response_body_buf.clear() yield from self.start_response_stream() yield from self.handle_event(ResponseData(self.stream_id, body_buf)) return False @@ -748,16 +751,30 @@ def handle_connect_finish(self): ) if 200 <= self.flow.response.status_code < 300: + yield HttpConnectedHook(self.flow) self.child_layer = self.child_layer or layer.NextLayer(self.context) - yield from self.child_layer.handle_event(events.Start()) self._handle_event = self.passthrough + yield from self.child_layer.handle_event(events.Start()) + else: + yield HttpConnectErrorHook(self.flow) + self.client_state = self.state_errored + self.flow.live = False + + content = self.flow.response.raw_content + done_after_headers = not (content or self.flow.response.trailers) + yield SendHttp( + ResponseHeaders(self.stream_id, self.flow.response, done_after_headers), + self.context.client, + ) + if content: + yield SendHttp(ResponseData(self.stream_id, content), self.context.client) + + if self.flow.response.trailers: yield SendHttp( - ResponseHeaders(self.stream_id, self.flow.response, True), + ResponseTrailers(self.stream_id, self.flow.response.trailers), self.context.client, ) - yield SendHttp(ResponseEndOfMessage(self.stream_id), self.context.client) - else: - yield from self.send_response() + yield SendHttp(ResponseEndOfMessage(self.stream_id), self.context.client) @expect(RequestData, RequestEndOfMessage, events.Event) def passthrough(self, event: events.Event) -> layer.CommandGenerator[None]: diff --git a/mitmproxy/proxy/layers/http/_hooks.py b/mitmproxy/proxy/layers/http/_hooks.py index 949c9a7e7d..80366644b4 100644 --- a/mitmproxy/proxy/layers/http/_hooks.py +++ b/mitmproxy/proxy/layers/http/_hooks.py @@ -96,3 +96,27 @@ class HttpConnectUpstreamHook(commands.StartHook): """ flow: http.HTTPFlow + + +@dataclass +class HttpConnectedHook(commands.StartHook): + """ + HTTP CONNECT was successful + + .. warning:: + This may fire before an upstream connection has been established + if `connection_strategy` is set to `lazy` (default) + """ + + flow: http.HTTPFlow + + +@dataclass +class HttpConnectErrorHook(commands.StartHook): + """ + HTTP CONNECT has failed. + This can happen when the upstream server is unreachable or proxy authentication is required. + In contrast to the `error` hook, `flow.error` is not guaranteed to be set. + """ + + flow: http.HTTPFlow diff --git a/mitmproxy/proxy/layers/http/_http2.py b/mitmproxy/proxy/layers/http/_http2.py index 0843850193..b2fa851e2c 100644 --- a/mitmproxy/proxy/layers/http/_http2.py +++ b/mitmproxy/proxy/layers/http/_http2.py @@ -604,7 +604,7 @@ def handle_h2_event(self, event: h2.events.Event) -> CommandGenerator[bool]: def split_pseudo_headers( - h2_headers: Sequence[tuple[bytes, bytes]] + h2_headers: Sequence[tuple[bytes, bytes]], ) -> tuple[dict[bytes, bytes], http.Headers]: pseudo_headers: dict[bytes, bytes] = {} i = 0 @@ -624,7 +624,7 @@ def split_pseudo_headers( def parse_h2_request_headers( - h2_headers: Sequence[tuple[bytes, bytes]] + h2_headers: Sequence[tuple[bytes, bytes]], ) -> tuple[str, int, bytes, bytes, bytes, bytes, http.Headers]: """Split HTTP/2 pseudo-headers from the actual headers and parse them.""" pseudo_headers, headers = split_pseudo_headers(h2_headers) @@ -654,7 +654,7 @@ def parse_h2_request_headers( def parse_h2_response_headers( - h2_headers: Sequence[tuple[bytes, bytes]] + h2_headers: Sequence[tuple[bytes, bytes]], ) -> tuple[int, http.Headers]: """Split HTTP/2 pseudo-headers from the actual headers and parse them.""" pseudo_headers, headers = split_pseudo_headers(h2_headers) diff --git a/mitmproxy/proxy/layers/http/_http3.py b/mitmproxy/proxy/layers/http/_http3.py index 51b04f5bc6..268f1c6c7c 100644 --- a/mitmproxy/proxy/layers/http/_http3.py +++ b/mitmproxy/proxy/layers/http/_http3.py @@ -26,7 +26,7 @@ from ._http2 import parse_h2_request_headers from ._http2 import parse_h2_response_headers from ._http_h3 import LayeredH3Connection -from ._http_h3 import StreamReset +from ._http_h3 import StreamClosed from ._http_h3 import TrailersReceived from mitmproxy import connection from mitmproxy import http @@ -39,7 +39,6 @@ from mitmproxy.proxy.layers.quic import error_code_to_str from mitmproxy.proxy.layers.quic import QuicConnectionClosed from mitmproxy.proxy.layers.quic import QuicStreamEvent -from mitmproxy.proxy.layers.quic import StopQuicStream from mitmproxy.proxy.utils import expect @@ -56,7 +55,6 @@ def __init__(self, context: context.Context, conn: connection.Connection): self.h3_conn = LayeredH3Connection( self.conn, is_client=self.conn is self.context.server ) - self._stream_protocol_errors: dict[int, int] = {} def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: if isinstance(event, events.Start): @@ -83,10 +81,6 @@ def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: elif isinstance(event, (RequestEndOfMessage, ResponseEndOfMessage)): self.h3_conn.end_stream(event.stream_id) elif isinstance(event, (RequestProtocolError, ResponseProtocolError)): - code = { - status_codes.CLIENT_CLOSED_REQUEST: H3ErrorCode.H3_REQUEST_CANCELLED.value, - }.get(event.code, H3ErrorCode.H3_INTERNAL_ERROR.value) - self._stream_protocol_errors[event.stream_id] = code send_error_message = ( isinstance(event, ResponseProtocolError) and not self.h3_conn.has_sent_headers(event.stream_id) @@ -107,7 +101,11 @@ def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: end_stream=True, ) else: - self.h3_conn.reset_stream(event.stream_id, code) + if event.code == status_codes.CLIENT_CLOSED_REQUEST: + code = H3ErrorCode.H3_REQUEST_CANCELLED.value + else: + code = H3ErrorCode.H3_INTERNAL_ERROR.value + self.h3_conn.close_stream(event.stream_id, code) else: # pragma: no cover raise AssertionError(f"Unexpected event: {event!r}") @@ -122,70 +120,56 @@ def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: # forward stream messages from the QUIC layer to the H3 connection elif isinstance(event, QuicStreamEvent): h3_events = self.h3_conn.handle_stream_event(event) - if event.stream_id in self._stream_protocol_errors: - # we already reset or ended the stream, tell the peer to stop - # (this is a noop if the peer already did the same) - yield StopQuicStream( - self.conn, - event.stream_id, - self._stream_protocol_errors[event.stream_id], - ) - else: - for h3_event in h3_events: - if isinstance(h3_event, StreamReset): - if h3_event.push_id is None: - err_str = error_code_to_str(h3_event.error_code) - err_code = { - H3ErrorCode.H3_REQUEST_CANCELLED.value: status_codes.CLIENT_CLOSED_REQUEST, - }.get(h3_event.error_code, self.ReceiveProtocolError.code) - yield ReceiveHttp( - self.ReceiveProtocolError( - h3_event.stream_id, - f"stream reset by client ({err_str})", - code=err_code, - ) - ) - elif isinstance(h3_event, DataReceived): - if h3_event.push_id is None: - if h3_event.data: - yield ReceiveHttp( - self.ReceiveData(h3_event.stream_id, h3_event.data) - ) - if h3_event.stream_ended: - yield ReceiveHttp( - self.ReceiveEndOfMessage(h3_event.stream_id) - ) - elif isinstance(h3_event, HeadersReceived): - if h3_event.push_id is None: - try: - receive_event = self.parse_headers(h3_event) - except ValueError as e: - self.h3_conn.close_connection( - error_code=H3ErrorCode.H3_GENERAL_PROTOCOL_ERROR, - reason_phrase=f"Invalid HTTP/3 request headers: {e}", - ) - else: - yield ReceiveHttp(receive_event) - if h3_event.stream_ended: - yield ReceiveHttp( - self.ReceiveEndOfMessage(h3_event.stream_id) - ) - elif isinstance(h3_event, TrailersReceived): - if h3_event.push_id is None: + for h3_event in h3_events: + if isinstance(h3_event, StreamClosed): + err_str = error_code_to_str(h3_event.error_code) + if h3_event.error_code == H3ErrorCode.H3_REQUEST_CANCELLED: + code = status_codes.CLIENT_CLOSED_REQUEST + else: + code = self.ReceiveProtocolError.code + yield ReceiveHttp( + self.ReceiveProtocolError( + h3_event.stream_id, + f"stream closed by client ({err_str})", + code=code, + ) + ) + elif isinstance(h3_event, DataReceived): + if h3_event.data: + yield ReceiveHttp( + self.ReceiveData(h3_event.stream_id, h3_event.data) + ) + if h3_event.stream_ended: + yield ReceiveHttp(self.ReceiveEndOfMessage(h3_event.stream_id)) + elif isinstance(h3_event, HeadersReceived): + try: + receive_event = self.parse_headers(h3_event) + except ValueError as e: + self.h3_conn.close_connection( + error_code=H3ErrorCode.H3_GENERAL_PROTOCOL_ERROR, + reason_phrase=f"Invalid HTTP/3 request headers: {e}", + ) + else: + yield ReceiveHttp(receive_event) + if h3_event.stream_ended: yield ReceiveHttp( - self.ReceiveTrailers( - h3_event.stream_id, http.Headers(h3_event.trailers) - ) + self.ReceiveEndOfMessage(h3_event.stream_id) ) - if h3_event.stream_ended: - yield ReceiveHttp( - self.ReceiveEndOfMessage(h3_event.stream_id) - ) - elif isinstance(h3_event, PushPromiseReceived): # pragma: no cover - # we don't support push - pass - else: # pragma: no cover - raise AssertionError(f"Unexpected event: {event!r}") + elif isinstance(h3_event, TrailersReceived): + yield ReceiveHttp( + self.ReceiveTrailers( + h3_event.stream_id, http.Headers(h3_event.trailers) + ) + ) + if h3_event.stream_ended: + yield ReceiveHttp(self.ReceiveEndOfMessage(h3_event.stream_id)) + elif isinstance(h3_event, PushPromiseReceived): # pragma: no cover + self.h3_conn.close_connection( + error_code=H3ErrorCode.H3_GENERAL_PROTOCOL_ERROR, + reason_phrase=f"Received HTTP/3 push promise, even though we signalled no support.", + ) + else: # pragma: no cover + raise AssertionError(f"Unexpected event: {event!r}") yield from self.h3_conn.transmit() # report a protocol error for all remaining open streams when a connection is closed @@ -193,7 +177,7 @@ def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: self._handle_event = self.done # type: ignore self.h3_conn.handle_connection_closed(event) msg = event.reason_phrase or error_code_to_str(event.error_code) - for stream_id in self.h3_conn.get_open_stream_ids(push_id=None): + for stream_id in self.h3_conn.get_open_stream_ids(): yield ReceiveHttp(self.ReceiveProtocolError(stream_id, msg)) else: # pragma: no cover diff --git a/mitmproxy/proxy/layers/http/_http_h2.py b/mitmproxy/proxy/layers/http/_http_h2.py index 60a88f6002..75d20dcbfe 100644 --- a/mitmproxy/proxy/layers/http/_http_h2.py +++ b/mitmproxy/proxy/layers/http/_http_h2.py @@ -68,12 +68,12 @@ def send_data( frame_size = len(data) assert pad_length is None - while frame_size > self.max_outbound_frame_size: - chunk_data = data[: self.max_outbound_frame_size] - self.send_data(stream_id, chunk_data, end_stream=False) + if frame_size > self.max_outbound_frame_size: + for start in range(0, frame_size, self.max_outbound_frame_size): + chunk = data[start : start + self.max_outbound_frame_size] + self.send_data(stream_id, chunk, end_stream=False) - data = data[self.max_outbound_frame_size :] - frame_size -= len(chunk_data) + return if self.stream_buffers.get(stream_id, None): # We already have some data buffered, let's append. diff --git a/mitmproxy/proxy/layers/http/_http_h3.py b/mitmproxy/proxy/layers/http/_http_h3.py index 1d1ea907d6..3ab4b35af6 100644 --- a/mitmproxy/proxy/layers/http/_http_h3.py +++ b/mitmproxy/proxy/layers/http/_http_h3.py @@ -7,7 +7,6 @@ from aioquic.h3.connection import H3Stream from aioquic.h3.connection import Headers from aioquic.h3.connection import HeadersState -from aioquic.h3.connection import StreamType from aioquic.h3.events import HeadersReceived from aioquic.quic.configuration import QuicConfiguration from aioquic.quic.events import StreamDataReceived @@ -21,8 +20,10 @@ from mitmproxy.proxy.layers.quic import QuicStreamDataReceived from mitmproxy.proxy.layers.quic import QuicStreamEvent from mitmproxy.proxy.layers.quic import QuicStreamReset +from mitmproxy.proxy.layers.quic import QuicStreamStopSending from mitmproxy.proxy.layers.quic import ResetQuicStream from mitmproxy.proxy.layers.quic import SendQuicStreamData +from mitmproxy.proxy.layers.quic import StopSendingQuicStream @dataclass @@ -40,24 +41,19 @@ class TrailersReceived(H3Event): stream_ended: bool "Whether the STREAM frame had the FIN bit set." - push_id: int | None = None - "The Push ID or `None` if this is not a push." - @dataclass -class StreamReset(H3Event): +class StreamClosed(H3Event): """ - The StreamReset event is fired whenever a stream is reset by the peer. + The StreamReset event is fired when the peer is sending a CLOSE_STREAM + or a STOP_SENDING frame. For HTTP/3, we don't differentiate between the two. """ stream_id: int "The ID of the stream that was reset." error_code: int - """The error code indicating why the stream was reset.""" - - push_id: int | None = None - "The Push ID or `None` if this is not a push." + """The error code indicating why the stream was closed.""" class MockQuic: @@ -101,6 +97,11 @@ def get_next_available_stream_id(self, is_unidirectional: bool = False) -> int: def reset_stream(self, stream_id: int, error_code: int) -> None: self.pending_commands.append(ResetQuicStream(self.conn, stream_id, error_code)) + def stop_send(self, stream_id: int, error_code: int) -> None: + self.pending_commands.append( + StopSendingQuicStream(self.conn, stream_id, error_code) + ) + def send_stream_data( self, stream_id: int, data: bytes, end_stream: bool = False ) -> None: @@ -122,8 +123,23 @@ def __init__( enable_webtransport: bool = False, ) -> None: self._mock = MockQuic(conn, is_client) + self._closed_streams: set[int] = set() + """ + We keep track of all stream IDs for which we have requested + STOP_SENDING to silently discard incoming data. + """ super().__init__(self._mock, enable_webtransport) # type: ignore + # aioquic's constructor sets and then uses _max_push_id. + # This is a hack to forcibly disable it. + @property + def _max_push_id(self) -> int | None: + return None + + @_max_push_id.setter + def _max_push_id(self, value): + pass + def _after_send(self, stream_id: int, end_stream: bool) -> None: # if the stream ended, `QuicConnection` has an assert that no further data is being sent # to catch this more early on, we set the header state on the `H3Stream` @@ -148,7 +164,7 @@ def _handle_request_or_push_frame( == HeadersState.AFTER_TRAILERS ): events[index] = TrailersReceived( - event.headers, event.stream_id, event.stream_ended, event.push_id + event.headers, event.stream_id, event.stream_ended ) return events @@ -176,15 +192,14 @@ def get_next_available_stream_id(self, is_unidirectional: bool = False): return self._quic.get_next_available_stream_id(is_unidirectional) - def get_open_stream_ids(self, push_id: int | None) -> Iterable[int]: - """Iterates over all non-special open streams, optionally for a given push id.""" + def get_open_stream_ids(self) -> Iterable[int]: + """Iterates over all non-special open streams""" return ( stream.stream_id for stream in self._stream.values() if ( - stream.push_id == push_id - and stream.stream_type == (None if push_id is None else StreamType.PUSH) + stream.stream_type is None and not ( stream.headers_recv_state == HeadersState.AFTER_TRAILERS and stream.headers_send_state == HeadersState.AFTER_TRAILERS @@ -200,17 +215,23 @@ def handle_stream_event(self, event: QuicStreamEvent) -> list[H3Event]: if self._is_done: return [] - # treat reset events similar to data events with end_stream=True - # We can receive multiple reset events as long as the final size does not change. - elif isinstance(event, QuicStreamReset): + elif isinstance(event, (QuicStreamReset, QuicStreamStopSending)): + self.close_stream( + event.stream_id, + event.error_code, + stop_send=isinstance(event, QuicStreamStopSending), + ) stream = self._get_or_create_stream(event.stream_id) stream.ended = True stream.headers_recv_state = HeadersState.AFTER_TRAILERS - return [StreamReset(event.stream_id, event.error_code, stream.push_id)] + return [StreamClosed(event.stream_id, event.error_code)] # convert data events from the QUIC layer back to aioquic events elif isinstance(event, QuicStreamDataReceived): - if self._get_or_create_stream(event.stream_id).ended: + # Discard contents if we have already sent STOP_SENDING on this stream. + if event.stream_id in self._closed_streams: + return [] + elif self._get_or_create_stream(event.stream_id).ended: # aioquic will not send us any data events once a stream has ended. # Instead, it will close the connection. We simulate this here for H3 tests. self.close_connection( @@ -235,13 +256,24 @@ def has_sent_headers(self, stream_id: int) -> bool: except KeyError: return False - def reset_stream(self, stream_id: int, error_code: int) -> None: - """Resets a stream that hasn't been ended locally yet.""" + def close_stream( + self, stream_id: int, error_code: int, stop_send: bool = True + ) -> None: + """Close a stream that hasn't been closed locally yet.""" + if stream_id not in self._closed_streams: + self._closed_streams.add(stream_id) - # set the header state and queue a reset event - stream = self._get_or_create_stream(stream_id) - stream.headers_send_state = HeadersState.AFTER_TRAILERS - self._quic.reset_stream(stream_id, error_code) + stream = self._get_or_create_stream(stream_id) + stream.headers_send_state = HeadersState.AFTER_TRAILERS + # https://www.rfc-editor.org/rfc/rfc9000.html#section-3.5-8 + # An endpoint that wishes to terminate both directions of + # a bidirectional stream can terminate one direction by + # sending a RESET_STREAM frame, and it can encourage prompt + # termination in the opposite direction by sending a + # STOP_SENDING frame. + self._mock.reset_stream(stream_id=stream_id, error_code=error_code) + if stop_send: + self._mock.stop_send(stream_id=stream_id, error_code=error_code) def send_data(self, stream_id: int, data: bytes, end_stream: bool = False) -> None: """Sends data over the given stream.""" @@ -284,6 +316,6 @@ def transmit(self) -> layer.CommandGenerator[None]: __all__ = [ "LayeredH3Connection", - "StreamReset", + "StreamClosed", "TrailersReceived", ] diff --git a/mitmproxy/proxy/layers/http/_upstream_proxy.py b/mitmproxy/proxy/layers/http/_upstream_proxy.py index 3220cf9307..f40b26ce6e 100644 --- a/mitmproxy/proxy/layers/http/_upstream_proxy.py +++ b/mitmproxy/proxy/layers/http/_upstream_proxy.py @@ -53,6 +53,9 @@ def start_handshake(self) -> layer.CommandGenerator[None]: authority = ( self.conn.address[0].encode("idna") + f":{self.conn.address[1]}".encode() ) + headers = http.Headers() + if self.context.options.http_connect_send_host_header: + headers.insert(0, b"Host", authority) flow.request = http.Request( host=self.conn.address[0], port=self.conn.address[1], @@ -61,7 +64,7 @@ def start_handshake(self) -> layer.CommandGenerator[None]: authority=authority, path=b"", http_version=b"HTTP/1.1", - headers=http.Headers(), + headers=headers, content=b"", trailers=None, timestamp_start=time.time(), diff --git a/mitmproxy/proxy/layers/quic.py b/mitmproxy/proxy/layers/quic.py deleted file mode 100644 index b3428fd2d7..0000000000 --- a/mitmproxy/proxy/layers/quic.py +++ /dev/null @@ -1,1256 +0,0 @@ -from __future__ import annotations - -import time -from collections.abc import Callable -from dataclasses import dataclass -from dataclasses import field -from logging import DEBUG -from logging import ERROR -from logging import WARNING -from ssl import VerifyMode - -from aioquic.buffer import Buffer as QuicBuffer -from aioquic.h3.connection import ErrorCode as H3ErrorCode -from aioquic.quic import events as quic_events -from aioquic.quic.configuration import QuicConfiguration -from aioquic.quic.connection import QuicConnection -from aioquic.quic.connection import QuicConnectionError -from aioquic.quic.connection import QuicConnectionState -from aioquic.quic.connection import QuicErrorCode -from aioquic.quic.connection import stream_is_client_initiated -from aioquic.quic.connection import stream_is_unidirectional -from aioquic.quic.packet import encode_quic_version_negotiation -from aioquic.quic.packet import PACKET_TYPE_INITIAL -from aioquic.quic.packet import pull_quic_header -from aioquic.quic.packet import QuicProtocolVersion -from aioquic.tls import CipherSuite -from aioquic.tls import HandshakeType -from cryptography import x509 -from cryptography.hazmat.primitives.asymmetric import dsa -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.hazmat.primitives.asymmetric import rsa - -from mitmproxy import certs -from mitmproxy import connection -from mitmproxy import ctx -from mitmproxy.net import tls -from mitmproxy.proxy import commands -from mitmproxy.proxy import context -from mitmproxy.proxy import events -from mitmproxy.proxy import layer -from mitmproxy.proxy import tunnel -from mitmproxy.proxy.layers.modes import TransparentProxy -from mitmproxy.proxy.layers.tcp import TCPLayer -from mitmproxy.proxy.layers.tls import TlsClienthelloHook -from mitmproxy.proxy.layers.tls import TlsEstablishedClientHook -from mitmproxy.proxy.layers.tls import TlsEstablishedServerHook -from mitmproxy.proxy.layers.tls import TlsFailedClientHook -from mitmproxy.proxy.layers.tls import TlsFailedServerHook -from mitmproxy.proxy.layers.udp import UDPLayer -from mitmproxy.tls import ClientHello -from mitmproxy.tls import ClientHelloData -from mitmproxy.tls import TlsData - - -@dataclass -class QuicTlsSettings: - """ - Settings necessary to establish QUIC's TLS context. - """ - - alpn_protocols: list[str] | None = None - """A list of supported ALPN protocols.""" - certificate: x509.Certificate | None = None - """The certificate to use for the connection.""" - certificate_chain: list[x509.Certificate] = field(default_factory=list) - """A list of additional certificates to send to the peer.""" - certificate_private_key: dsa.DSAPrivateKey | ec.EllipticCurvePrivateKey | rsa.RSAPrivateKey | None = None - """The certificate's private key.""" - cipher_suites: list[CipherSuite] | None = None - """An optional list of allowed/advertised cipher suites.""" - ca_path: str | None = None - """An optional path to a directory that contains the necessary information to verify the peer certificate.""" - ca_file: str | None = None - """An optional path to a PEM file that will be used to verify the peer certificate.""" - verify_mode: VerifyMode | None = None - """An optional flag that specifies how/if the peer's certificate should be validated.""" - - -@dataclass -class QuicTlsData(TlsData): - """ - Event data for `quic_start_client` and `quic_start_server` event hooks. - """ - - settings: QuicTlsSettings | None = None - """ - The associated `QuicTlsSettings` object. - This will be set by an addon in the `quic_start_*` event hooks. - """ - - -@dataclass -class QuicStartClientHook(commands.StartHook): - """ - TLS negotiation between mitmproxy and a client over QUIC is about to start. - - An addon is expected to initialize data.settings. - (by default, this is done by `mitmproxy.addons.tlsconfig`) - """ - - data: QuicTlsData - - -@dataclass -class QuicStartServerHook(commands.StartHook): - """ - TLS negotiation between mitmproxy and a server over QUIC is about to start. - - An addon is expected to initialize data.settings. - (by default, this is done by `mitmproxy.addons.tlsconfig`) - """ - - data: QuicTlsData - - -@dataclass -class QuicStreamEvent(events.ConnectionEvent): - """Base class for all QUIC stream events.""" - - stream_id: int - """The ID of the stream the event was fired for.""" - - -@dataclass -class QuicStreamDataReceived(QuicStreamEvent): - """Event that is fired whenever data is received on a stream.""" - - data: bytes - """The data which was received.""" - end_stream: bool - """Whether the STREAM frame had the FIN bit set.""" - - -@dataclass -class QuicStreamReset(QuicStreamEvent): - """Event that is fired when the remote peer resets a stream.""" - - error_code: int - """The error code that triggered the reset.""" - - -class QuicStreamCommand(commands.ConnectionCommand): - """Base class for all QUIC stream commands.""" - - stream_id: int - """The ID of the stream the command was issued for.""" - - def __init__(self, connection: connection.Connection, stream_id: int) -> None: - super().__init__(connection) - self.stream_id = stream_id - - -class SendQuicStreamData(QuicStreamCommand): - """Command that sends data on a stream.""" - - data: bytes - """The data which should be sent.""" - end_stream: bool - """Whether the FIN bit should be set in the STREAM frame.""" - - def __init__( - self, - connection: connection.Connection, - stream_id: int, - data: bytes, - end_stream: bool = False, - ) -> None: - super().__init__(connection, stream_id) - self.data = data - self.end_stream = end_stream - - -class ResetQuicStream(QuicStreamCommand): - """Abruptly terminate the sending part of a stream.""" - - error_code: int - """An error code indicating why the stream is being reset.""" - - def __init__( - self, connection: connection.Connection, stream_id: int, error_code: int - ) -> None: - super().__init__(connection, stream_id) - self.error_code = error_code - - -class StopQuicStream(QuicStreamCommand): - """Request termination of the receiving part of a stream.""" - - error_code: int - """An error code indicating why the stream is being stopped.""" - - def __init__( - self, connection: connection.Connection, stream_id: int, error_code: int - ) -> None: - super().__init__(connection, stream_id) - self.error_code = error_code - - -class CloseQuicConnection(commands.CloseConnection): - """Close a QUIC connection.""" - - error_code: int - "The error code which was specified when closing the connection." - - frame_type: int | None - "The frame type which caused the connection to be closed, or `None`." - - reason_phrase: str - "The human-readable reason for which the connection was closed." - - # XXX: A bit much boilerplate right now. Should switch to dataclasses. - def __init__( - self, - conn: connection.Connection, - error_code: int, - frame_type: int | None, - reason_phrase: str, - ) -> None: - super().__init__(conn) - self.error_code = error_code - self.frame_type = frame_type - self.reason_phrase = reason_phrase - - -class QuicConnectionClosed(events.ConnectionClosed): - """QUIC connection has been closed.""" - - error_code: int - "The error code which was specified when closing the connection." - - frame_type: int | None - "The frame type which caused the connection to be closed, or `None`." - - reason_phrase: str - "The human-readable reason for which the connection was closed." - - def __init__( - self, - conn: connection.Connection, - error_code: int, - frame_type: int | None, - reason_phrase: str, - ) -> None: - super().__init__(conn) - self.error_code = error_code - self.frame_type = frame_type - self.reason_phrase = reason_phrase - - -class QuicSecretsLogger: - logger: tls.MasterSecretLogger - - def __init__(self, logger: tls.MasterSecretLogger) -> None: - super().__init__() - self.logger = logger - - def write(self, s: str) -> int: - if s[-1:] == "\n": - s = s[:-1] - data = s.encode("ascii") - self.logger(None, data) # type: ignore - return len(data) + 1 - - def flush(self) -> None: - # done by the logger during write - pass - - -def error_code_to_str(error_code: int) -> str: - """Returns the corresponding name of the given error code or a string containing its numeric value.""" - - try: - return H3ErrorCode(error_code).name - except ValueError: - try: - return QuicErrorCode(error_code).name - except ValueError: - return f"unknown error (0x{error_code:x})" - - -def is_success_error_code(error_code: int) -> bool: - """Returns whether the given error code actually indicates no error.""" - - return error_code in (QuicErrorCode.NO_ERROR, H3ErrorCode.H3_NO_ERROR) - - -def tls_settings_to_configuration( - settings: QuicTlsSettings, - is_client: bool, - server_name: str | None = None, -) -> QuicConfiguration: - """Converts `QuicTlsSettings` to `QuicConfiguration`.""" - - return QuicConfiguration( - alpn_protocols=settings.alpn_protocols, - is_client=is_client, - secrets_log_file=( - QuicSecretsLogger(tls.log_master_secret) # type: ignore - if tls.log_master_secret is not None - else None - ), - server_name=server_name, - cafile=settings.ca_file, - capath=settings.ca_path, - certificate=settings.certificate, - certificate_chain=settings.certificate_chain, - cipher_suites=settings.cipher_suites, - private_key=settings.certificate_private_key, - verify_mode=settings.verify_mode, - max_datagram_frame_size=65536, - ) - - -@dataclass -class QuicClientHello(Exception): - """Helper error only used in `quic_parse_client_hello`.""" - - data: bytes - - -def quic_parse_client_hello(data: bytes) -> ClientHello: - """Helper function that parses a client hello packet.""" - - # ensure the first packet is indeed the initial one - buffer = QuicBuffer(data=data) - header = pull_quic_header(buffer, 8) - if header.packet_type != PACKET_TYPE_INITIAL: - raise ValueError("Packet is not initial one.") - - # patch aioquic to intercept the client hello - quic = QuicConnection( - configuration=QuicConfiguration( - is_client=False, - certificate="", - private_key="", - ), - original_destination_connection_id=header.destination_cid, - ) - _initialize = quic._initialize - - def server_handle_hello_replacement( - input_buf: QuicBuffer, - initial_buf: QuicBuffer, - handshake_buf: QuicBuffer, - onertt_buf: QuicBuffer, - ) -> None: - assert input_buf.pull_uint8() == HandshakeType.CLIENT_HELLO - length = 0 - for b in input_buf.pull_bytes(3): - length = (length << 8) | b - offset = input_buf.tell() - raise QuicClientHello(input_buf.data_slice(offset, offset + length)) - - def initialize_replacement(peer_cid: bytes) -> None: - try: - return _initialize(peer_cid) - finally: - quic.tls._server_handle_hello = server_handle_hello_replacement # type: ignore - - quic._initialize = initialize_replacement # type: ignore - try: - quic.receive_datagram(data, ("0.0.0.0", 0), now=0) - except QuicClientHello as hello: - try: - return ClientHello(hello.data) - except EOFError as e: - raise ValueError("Invalid ClientHello data.") from e - except QuicConnectionError as e: - raise ValueError(e.reason_phrase) from e - raise ValueError("No ClientHello returned.") - - -class QuicStreamNextLayer(layer.NextLayer): - """`NextLayer` variant that callbacks `QuicStreamLayer` after layer decision.""" - - def __init__( - self, - context: context.Context, - stream: QuicStreamLayer, - ask_on_start: bool = False, - ) -> None: - super().__init__(context, ask_on_start) - self._stream = stream - self._layer: layer.Layer | None = None - - @property # type: ignore - def layer(self) -> layer.Layer | None: # type: ignore - return self._layer - - @layer.setter - def layer(self, value: layer.Layer | None) -> None: - self._layer = value - if self._layer: - self._stream.refresh_metadata() - - -class QuicStreamLayer(layer.Layer): - """ - Layer for QUIC streams. - Serves as a marker for NextLayer and keeps track of the connection states. - """ - - client: connection.Client - """Virtual client connection for this stream. Use this in QuicRawLayer instead of `context.client`.""" - server: connection.Server - """Virtual server connection for this stream. Use this in QuicRawLayer instead of `context.server`.""" - child_layer: layer.Layer - """The stream's child layer.""" - - def __init__(self, context: context.Context, ignore: bool, stream_id: int) -> None: - # we mustn't reuse the client from the QUIC connection, as the state and protocol differs - self.client = context.client = context.client.copy() - self.client.transport_protocol = "tcp" - self.client.state = connection.ConnectionState.OPEN - - # unidirectional client streams are not fully open, set the appropriate state - if stream_is_unidirectional(stream_id): - self.client.state = ( - connection.ConnectionState.CAN_READ - if stream_is_client_initiated(stream_id) - else connection.ConnectionState.CAN_WRITE - ) - self._client_stream_id = stream_id - - # start with a closed server - self.server = context.server = connection.Server( - address=context.server.address, - transport_protocol="tcp", - ) - self._server_stream_id: int | None = None - - # ignored connections will be assigned a TCPLayer immediately - super().__init__(context) - self.child_layer = ( - TCPLayer(context, ignore=True) - if ignore - else QuicStreamNextLayer(context, self) - ) - self.refresh_metadata() - - # we don't handle any events, pass everything to the child layer - self.handle_event = self.child_layer.handle_event # type: ignore - self._handle_event = self.child_layer._handle_event # type: ignore - - def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: - raise AssertionError # pragma: no cover - - def open_server_stream(self, server_stream_id) -> None: - assert self._server_stream_id is None - self._server_stream_id = server_stream_id - self.server.timestamp_start = time.time() - self.server.state = ( - ( - connection.ConnectionState.CAN_WRITE - if stream_is_client_initiated(server_stream_id) - else connection.ConnectionState.CAN_READ - ) - if stream_is_unidirectional(server_stream_id) - else connection.ConnectionState.OPEN - ) - self.refresh_metadata() - - def refresh_metadata(self) -> None: - # find the first transport layer - child_layer: layer.Layer | None = self.child_layer - while True: - if isinstance(child_layer, layer.NextLayer): - child_layer = child_layer.layer - elif isinstance(child_layer, tunnel.TunnelLayer): - child_layer = child_layer.child_layer - else: - break # pragma: no cover - if isinstance(child_layer, (UDPLayer, TCPLayer)) and child_layer.flow: - child_layer.flow.metadata[ - "quic_is_unidirectional" - ] = stream_is_unidirectional(self._client_stream_id) - child_layer.flow.metadata["quic_initiator"] = ( - "client" - if stream_is_client_initiated(self._client_stream_id) - else "server" - ) - child_layer.flow.metadata["quic_stream_id_client"] = self._client_stream_id - child_layer.flow.metadata["quic_stream_id_server"] = self._server_stream_id - - def stream_id(self, client: bool) -> int | None: - return self._client_stream_id if client else self._server_stream_id - - -class RawQuicLayer(layer.Layer): - """ - This layer is responsible for de-multiplexing QUIC streams into an individual layer stack per stream. - """ - - ignore: bool - """Indicates whether traffic should be routed as-is.""" - datagram_layer: layer.Layer - """ - The layer that is handling datagrams over QUIC. It's like a child_layer, but with a forked context. - Instead of having a datagram-equivalent for all `QuicStream*` classes, we use `SendData` and `DataReceived` instead. - There is also no need for another `NextLayer` marker, as a missing `QuicStreamLayer` implies UDP, - and the connection state is the same as the one of the underlying QUIC connection. - """ - client_stream_ids: dict[int, QuicStreamLayer] - """Maps stream IDs from the client connection to stream layers.""" - server_stream_ids: dict[int, QuicStreamLayer] - """Maps stream IDs from the server connection to stream layers.""" - connections: dict[connection.Connection, layer.Layer] - """Maps connections to layers.""" - command_sources: dict[commands.Command, layer.Layer] - """Keeps track of blocking commands and wakeup requests.""" - next_stream_id: list[int] - """List containing the next stream ID for all four is_unidirectional/is_client combinations.""" - - def __init__(self, context: context.Context, ignore: bool = False) -> None: - super().__init__(context) - self.ignore = ignore - self.datagram_layer = ( - UDPLayer(self.context.fork(), ignore=True) - if ignore - else layer.NextLayer(self.context.fork()) - ) - self.client_stream_ids = {} - self.server_stream_ids = {} - self.connections = { - context.client: self.datagram_layer, - context.server: self.datagram_layer, - } - self.command_sources = {} - self.next_stream_id = [0, 1, 2, 3] - - def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: - # we treat the datagram layer as child layer, so forward Start - if isinstance(event, events.Start): - if self.context.server.timestamp_start is None: - err = yield commands.OpenConnection(self.context.server) - if err: - yield commands.CloseConnection(self.context.client) - self._handle_event = self.done # type: ignore - return - yield from self.event_to_child(self.datagram_layer, event) - - # properly forward completion events based on their command - elif isinstance(event, events.CommandCompleted): - yield from self.event_to_child( - self.command_sources.pop(event.command), event - ) - - # route injected messages based on their connections (prefer client, fallback to server) - elif isinstance(event, events.MessageInjected): - if event.flow.client_conn in self.connections: - yield from self.event_to_child( - self.connections[event.flow.client_conn], event - ) - elif event.flow.server_conn in self.connections: - yield from self.event_to_child( - self.connections[event.flow.server_conn], event - ) - else: - raise AssertionError(f"Flow not associated: {event.flow!r}") - - # handle stream events targeting this context - elif isinstance(event, QuicStreamEvent) and ( - event.connection is self.context.client - or event.connection is self.context.server - ): - from_client = event.connection is self.context.client - - # fetch or create the layer - stream_ids = ( - self.client_stream_ids if from_client else self.server_stream_ids - ) - if event.stream_id in stream_ids: - stream_layer = stream_ids[event.stream_id] - else: - # ensure we haven't just forgotten to register the ID - assert stream_is_client_initiated(event.stream_id) == from_client - - # for server-initiated streams we need to open the client as well - if from_client: - client_stream_id = event.stream_id - server_stream_id = None - else: - client_stream_id = self.get_next_available_stream_id( - is_client=False, - is_unidirectional=stream_is_unidirectional(event.stream_id), - ) - server_stream_id = event.stream_id - - # create, register and start the layer - stream_layer = QuicStreamLayer( - self.context.fork(), self.ignore, client_stream_id - ) - self.client_stream_ids[client_stream_id] = stream_layer - if server_stream_id is not None: - stream_layer.open_server_stream(server_stream_id) - self.server_stream_ids[server_stream_id] = stream_layer - self.connections[stream_layer.client] = stream_layer - self.connections[stream_layer.server] = stream_layer - yield from self.event_to_child(stream_layer, events.Start()) - - # forward data and close events - conn = stream_layer.client if from_client else stream_layer.server - if isinstance(event, QuicStreamDataReceived): - if event.data: - yield from self.event_to_child( - stream_layer, events.DataReceived(conn, event.data) - ) - if event.end_stream: - yield from self.close_stream_layer(stream_layer, from_client) - elif isinstance(event, QuicStreamReset): - # preserve stream resets - for command in self.close_stream_layer(stream_layer, from_client): - if ( - isinstance(command, SendQuicStreamData) - and command.stream_id == stream_layer.stream_id(not from_client) - and command.end_stream - and not command.data - ): - yield ResetQuicStream( - command.connection, command.stream_id, event.error_code - ) - else: - yield command - else: - raise AssertionError(f"Unexpected stream event: {event!r}") - - # handle close events that target this context - elif isinstance(event, QuicConnectionClosed) and ( - event.connection is self.context.client - or event.connection is self.context.server - ): - from_client = event.connection is self.context.client - other_conn = self.context.server if from_client else self.context.client - - # be done if both connections are closed - if other_conn.connected: - yield CloseQuicConnection( - other_conn, event.error_code, event.frame_type, event.reason_phrase - ) - else: - self._handle_event = self.done # type: ignore - - # always forward to the datagram layer and swallow `CloseConnection` commands - for command in self.event_to_child(self.datagram_layer, event): - if ( - not isinstance(command, commands.CloseConnection) - or command.connection is not other_conn - ): - yield command - - # forward to either the client or server connection of stream layers and swallow empty stream end - for conn, child_layer in self.connections.items(): - if isinstance(child_layer, QuicStreamLayer) and ( - (conn is child_layer.client) - if from_client - else (conn is child_layer.server) - ): - conn.state &= ~connection.ConnectionState.CAN_WRITE - for command in self.close_stream_layer(child_layer, from_client): - if not isinstance(command, SendQuicStreamData) or command.data: - yield command - - # all other connection events are routed to their corresponding layer - elif isinstance(event, events.ConnectionEvent): - yield from self.event_to_child(self.connections[event.connection], event) - - else: - raise AssertionError(f"Unexpected event: {event!r}") - - def close_stream_layer( - self, stream_layer: QuicStreamLayer, client: bool - ) -> layer.CommandGenerator[None]: - """Closes the incoming part of a connection.""" - - conn = stream_layer.client if client else stream_layer.server - conn.state &= ~connection.ConnectionState.CAN_READ - assert conn.timestamp_start is not None - if conn.timestamp_end is None: - conn.timestamp_end = time.time() - yield from self.event_to_child(stream_layer, events.ConnectionClosed(conn)) - - def event_to_child( - self, child_layer: layer.Layer, event: events.Event - ) -> layer.CommandGenerator[None]: - """Forwards events to child layers and translates commands.""" - - for command in child_layer.handle_event(event): - # intercept commands for streams connections - if ( - isinstance(child_layer, QuicStreamLayer) - and isinstance(command, commands.ConnectionCommand) - and ( - command.connection is child_layer.client - or command.connection is child_layer.server - ) - ): - # get the target connection and stream ID - to_client = command.connection is child_layer.client - quic_conn = self.context.client if to_client else self.context.server - stream_id = child_layer.stream_id(to_client) - - # write data and check CloseConnection wasn't called before - if isinstance(command, commands.SendData): - assert stream_id is not None - if command.connection.state & connection.ConnectionState.CAN_WRITE: - yield SendQuicStreamData(quic_conn, stream_id, command.data) - - # send a FIN and optionally also a STOP frame - elif isinstance(command, commands.CloseConnection): - assert stream_id is not None - if command.connection.state & connection.ConnectionState.CAN_WRITE: - command.connection.state &= ( - ~connection.ConnectionState.CAN_WRITE - ) - yield SendQuicStreamData( - quic_conn, stream_id, b"", end_stream=True - ) - # XXX: Use `command.connection.state & connection.ConnectionState.CAN_READ` instead? - only_close_our_half = ( - isinstance(command, commands.CloseTcpConnection) - and command.half_close - ) - if not only_close_our_half: - if stream_is_client_initiated( - stream_id - ) == to_client or not stream_is_unidirectional(stream_id): - yield StopQuicStream( - quic_conn, stream_id, QuicErrorCode.NO_ERROR - ) - yield from self.close_stream_layer(child_layer, to_client) - - # open server connections by reserving the next stream ID - elif isinstance(command, commands.OpenConnection): - assert not to_client - assert stream_id is None - client_stream_id = child_layer.stream_id(client=True) - assert client_stream_id is not None - stream_id = self.get_next_available_stream_id( - is_client=True, - is_unidirectional=stream_is_unidirectional(client_stream_id), - ) - child_layer.open_server_stream(stream_id) - self.server_stream_ids[stream_id] = child_layer - yield from self.event_to_child( - child_layer, events.OpenConnectionCompleted(command, None) - ) - - else: - raise AssertionError( - f"Unexpected stream connection command: {command!r}" - ) - - # remember blocking and wakeup commands - else: - if command.blocking or isinstance(command, commands.RequestWakeup): - self.command_sources[command] = child_layer - if isinstance(command, commands.OpenConnection): - self.connections[command.connection] = child_layer - yield command - - def get_next_available_stream_id( - self, is_client: bool, is_unidirectional: bool = False - ) -> int: - index = (int(is_unidirectional) << 1) | int(not is_client) - stream_id = self.next_stream_id[index] - self.next_stream_id[index] = stream_id + 4 - return stream_id - - def done(self, _) -> layer.CommandGenerator[None]: - yield from () - - -class QuicLayer(tunnel.TunnelLayer): - quic: QuicConnection | None = None - tls: QuicTlsSettings | None = None - - def __init__( - self, - context: context.Context, - conn: connection.Connection, - time: Callable[[], float] | None, - ) -> None: - super().__init__(context, tunnel_connection=conn, conn=conn) - self.child_layer = layer.NextLayer(self.context, ask_on_start=True) - self._time = time or ctx.master.event_loop.time - self._wakeup_commands: dict[commands.RequestWakeup, float] = dict() - conn.tls = True - - def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: - if isinstance(event, events.Wakeup) and event.command in self._wakeup_commands: - # TunnelLayer has no understanding of wakeups, so we turn this into an empty DataReceived event - # which TunnelLayer recognizes as belonging to our connection. - assert self.quic - timer = self._wakeup_commands.pop(event.command) - if self.quic._state is not QuicConnectionState.TERMINATED: - self.quic.handle_timer(now=max(timer, self._time())) - yield from super()._handle_event( - events.DataReceived(self.tunnel_connection, b"") - ) - else: - yield from super()._handle_event(event) - - def event_to_child(self, event: events.Event) -> layer.CommandGenerator[None]: - # the parent will call _handle_command multiple times, we transmit cumulative afterwards - # this will reduce the number of sends, especially if data=b"" and end_stream=True - yield from super().event_to_child(event) - if self.quic: - yield from self.tls_interact() - - def _handle_command( - self, command: commands.Command - ) -> layer.CommandGenerator[None]: - """Turns stream commands into aioquic connection invocations.""" - if isinstance(command, QuicStreamCommand) and command.connection is self.conn: - assert self.quic - if isinstance(command, SendQuicStreamData): - self.quic.send_stream_data( - command.stream_id, command.data, command.end_stream - ) - elif isinstance(command, ResetQuicStream): - self.quic.reset_stream(command.stream_id, command.error_code) - elif isinstance(command, StopQuicStream): - # the stream might have already been closed, check before stopping - if command.stream_id in self.quic._streams: - self.quic.stop_stream(command.stream_id, command.error_code) - else: - raise AssertionError(f"Unexpected stream command: {command!r}") - else: - yield from super()._handle_command(command) - - def start_tls( - self, original_destination_connection_id: bytes | None - ) -> layer.CommandGenerator[None]: - """Initiates the aioquic connection.""" - - # must only be called if QUIC is uninitialized - assert not self.quic - assert not self.tls - - # query addons to provide the necessary TLS settings - tls_data = QuicTlsData(self.conn, self.context) - if self.conn is self.context.client: - yield QuicStartClientHook(tls_data) - else: - yield QuicStartServerHook(tls_data) - if not tls_data.settings: - yield commands.Log( - f"No QUIC context was provided, failing connection.", ERROR - ) - yield commands.CloseConnection(self.conn) - return - - # build the aioquic connection - configuration = tls_settings_to_configuration( - settings=tls_data.settings, - is_client=self.conn is self.context.server, - server_name=self.conn.sni, - ) - self.quic = QuicConnection( - configuration=configuration, - original_destination_connection_id=original_destination_connection_id, - ) - self.tls = tls_data.settings - - # if we act as client, connect to upstream - if original_destination_connection_id is None: - self.quic.connect(self.conn.peername, now=self._time()) - yield from self.tls_interact() - - def tls_interact(self) -> layer.CommandGenerator[None]: - """Retrieves all pending outgoing packets from aioquic and sends the data.""" - - # send all queued datagrams - assert self.quic - for data, addr in self.quic.datagrams_to_send(now=self._time()): - assert addr == self.conn.peername - yield commands.SendData(self.tunnel_connection, data) - - # request a new wakeup if all pending requests trigger at a later time - timer = self.quic.get_timer() - if timer is not None and not any( - existing <= timer for existing in self._wakeup_commands.values() - ): - command = commands.RequestWakeup(timer - self._time()) - self._wakeup_commands[command] = timer - yield command - - def receive_handshake_data( - self, data: bytes - ) -> layer.CommandGenerator[tuple[bool, str | None]]: - assert self.quic - - # forward incoming data to aioquic - if data: - self.quic.receive_datagram(data, self.conn.peername, now=self._time()) - - # handle pre-handshake events - while event := self.quic.next_event(): - if isinstance(event, quic_events.ConnectionTerminated): - err = event.reason_phrase or error_code_to_str(event.error_code) - return False, err - elif isinstance(event, quic_events.HandshakeCompleted): - # concatenate all peer certificates - all_certs: list[x509.Certificate] = [] - if self.quic.tls._peer_certificate: - all_certs.append(self.quic.tls._peer_certificate) - all_certs.extend(self.quic.tls._peer_certificate_chain) - - # set the connection's TLS properties - self.conn.timestamp_tls_setup = time.time() - if event.alpn_protocol: - self.conn.alpn = event.alpn_protocol.encode("ascii") - self.conn.certificate_list = [certs.Cert(cert) for cert in all_certs] - assert self.quic.tls.key_schedule - self.conn.cipher = self.quic.tls.key_schedule.cipher_suite.name - self.conn.tls_version = "QUIC" - - # log the result and report the success to addons - if self.debug: - yield commands.Log( - f"{self.debug}[quic] tls established: {self.conn}", DEBUG - ) - if self.conn is self.context.client: - yield TlsEstablishedClientHook( - QuicTlsData(self.conn, self.context, settings=self.tls) - ) - else: - yield TlsEstablishedServerHook( - QuicTlsData(self.conn, self.context, settings=self.tls) - ) - - yield from self.tls_interact() - return True, None - elif isinstance( - event, - ( - quic_events.ConnectionIdIssued, - quic_events.ConnectionIdRetired, - quic_events.PingAcknowledged, - quic_events.ProtocolNegotiated, - ), - ): - pass - else: - raise AssertionError(f"Unexpected event: {event!r}") - - # transmit buffered data and re-arm timer - yield from self.tls_interact() - return False, None - - def on_handshake_error(self, err: str) -> layer.CommandGenerator[None]: - self.conn.error = err - if self.conn is self.context.client: - yield TlsFailedClientHook( - QuicTlsData(self.conn, self.context, settings=self.tls) - ) - else: - yield TlsFailedServerHook( - QuicTlsData(self.conn, self.context, settings=self.tls) - ) - yield from super().on_handshake_error(err) - - def receive_data(self, data: bytes) -> layer.CommandGenerator[None]: - assert self.quic - - # forward incoming data to aioquic - if data: - self.quic.receive_datagram(data, self.conn.peername, now=self._time()) - - # handle post-handshake events - while event := self.quic.next_event(): - if isinstance(event, quic_events.ConnectionTerminated): - if self.debug: - reason = event.reason_phrase or error_code_to_str(event.error_code) - yield commands.Log( - f"{self.debug}[quic] close_notify {self.conn} (reason={reason})", - DEBUG, - ) - # We don't rely on `ConnectionTerminated` to dispatch `QuicConnectionClosed`, because - # after aioquic receives a termination frame, it still waits for the next `handle_timer` - # before returning `ConnectionTerminated` in `next_event`. In the meantime, the underlying - # connection could be closed. Therefore, we instead dispatch on `ConnectionClosed` and simply - # close the connection here. - yield commands.CloseConnection(self.tunnel_connection) - return # we don't handle any further events, nor do/can we transmit data, so exit - elif isinstance(event, quic_events.DatagramFrameReceived): - yield from self.event_to_child( - events.DataReceived(self.conn, event.data) - ) - elif isinstance(event, quic_events.StreamDataReceived): - yield from self.event_to_child( - QuicStreamDataReceived( - self.conn, event.stream_id, event.data, event.end_stream - ) - ) - elif isinstance(event, quic_events.StreamReset): - yield from self.event_to_child( - QuicStreamReset(self.conn, event.stream_id, event.error_code) - ) - elif isinstance( - event, - ( - quic_events.ConnectionIdIssued, - quic_events.ConnectionIdRetired, - quic_events.PingAcknowledged, - quic_events.ProtocolNegotiated, - ), - ): - pass - else: - raise AssertionError(f"Unexpected event: {event!r}") - - # transmit buffered data and re-arm timer - yield from self.tls_interact() - - def receive_close(self) -> layer.CommandGenerator[None]: - assert self.quic - # if `_close_event` is not set, the underlying connection has been closed - # we turn this into a QUIC close event as well - close_event = self.quic._close_event or quic_events.ConnectionTerminated( - QuicErrorCode.NO_ERROR, None, "Connection closed." - ) - yield from self.event_to_child( - QuicConnectionClosed( - self.conn, - close_event.error_code, - close_event.frame_type, - close_event.reason_phrase, - ) - ) - - def send_data(self, data: bytes) -> layer.CommandGenerator[None]: - # non-stream data uses datagram frames - assert self.quic - if data: - self.quic.send_datagram_frame(data) - yield from self.tls_interact() - - def send_close( - self, command: commands.CloseConnection - ) -> layer.CommandGenerator[None]: - # properly close the QUIC connection - if self.quic: - if isinstance(command, CloseQuicConnection): - self.quic.close( - command.error_code, command.frame_type, command.reason_phrase - ) - else: - self.quic.close() - yield from self.tls_interact() - yield from super().send_close(command) - - -class ServerQuicLayer(QuicLayer): - """ - This layer establishes QUIC for a single server connection. - """ - - wait_for_clienthello: bool = False - - def __init__( - self, - context: context.Context, - conn: connection.Server | None = None, - time: Callable[[], float] | None = None, - ): - super().__init__(context, conn or context.server, time) - - def start_handshake(self) -> layer.CommandGenerator[None]: - wait_for_clienthello = not self.command_to_reply_to and isinstance( - self.child_layer, ClientQuicLayer - ) - if wait_for_clienthello: - self.wait_for_clienthello = True - self.tunnel_state = tunnel.TunnelState.CLOSED - else: - yield from self.start_tls(None) - - def event_to_child(self, event: events.Event) -> layer.CommandGenerator[None]: - if self.wait_for_clienthello: - for command in super().event_to_child(event): - if ( - isinstance(command, commands.OpenConnection) - and command.connection == self.conn - ): - self.wait_for_clienthello = False - else: - yield command - else: - yield from super().event_to_child(event) - - def on_handshake_error(self, err: str) -> layer.CommandGenerator[None]: - yield commands.Log(f"Server QUIC handshake failed. {err}", level=WARNING) - yield from super().on_handshake_error(err) - - -class ClientQuicLayer(QuicLayer): - """ - This layer establishes QUIC on a single client connection. - """ - - server_tls_available: bool - """Indicates whether the parent layer is a ServerQuicLayer.""" - - def __init__( - self, context: context.Context, time: Callable[[], float] | None = None - ) -> None: - # same as ClientTLSLayer, we might be nested in some other transport - if context.client.tls: - context.client.alpn = None - context.client.cipher = None - context.client.sni = None - context.client.timestamp_tls_setup = None - context.client.tls_version = None - context.client.certificate_list = [] - context.client.mitmcert = None - context.client.alpn_offers = [] - context.client.cipher_list = [] - - super().__init__(context, context.client, time) - self.server_tls_available = len(self.context.layers) >= 2 and isinstance( - self.context.layers[-2], ServerQuicLayer - ) - - def start_handshake(self) -> layer.CommandGenerator[None]: - yield from () - - def receive_handshake_data( - self, data: bytes - ) -> layer.CommandGenerator[tuple[bool, str | None]]: - if isinstance(self.context.layers[0], TransparentProxy): # pragma: no cover - yield commands.Log( - f"Swallowing QUIC handshake because HTTP/3 does not support transparent mode yet.", - DEBUG, - ) - return False, None - if not self.context.options.http3: - yield commands.Log( - f"Swallowing QUIC handshake because HTTP/3 is disabled.", DEBUG - ) - return False, None - - # if we already had a valid client hello, don't process further packets - if self.tls: - return (yield from super().receive_handshake_data(data)) - - # fail if the received data is not a QUIC packet - buffer = QuicBuffer(data=data) - try: - header = pull_quic_header(buffer) - except TypeError: - return False, f"Cannot parse QUIC header: Malformed head ({data.hex()})" - except ValueError as e: - return False, f"Cannot parse QUIC header: {e} ({data.hex()})" - - # negotiate version, support all versions known to aioquic - supported_versions = [ - version.value - for version in QuicProtocolVersion - if version is not QuicProtocolVersion.NEGOTIATION - ] - if header.version is not None and header.version not in supported_versions: - yield commands.SendData( - self.tunnel_connection, - encode_quic_version_negotiation( - source_cid=header.destination_cid, - destination_cid=header.source_cid, - supported_versions=supported_versions, - ), - ) - return False, None - - # ensure it's (likely) a client handshake packet - if len(data) < 1200 or header.packet_type != PACKET_TYPE_INITIAL: - return ( - False, - f"Invalid handshake received, roaming not supported. ({data.hex()})", - ) - - # extract the client hello - try: - client_hello = quic_parse_client_hello(data) - except ValueError as e: - return False, f"Cannot parse ClientHello: {str(e)} ({data.hex()})" - - # copy the client hello information - self.conn.sni = client_hello.sni - self.conn.alpn_offers = client_hello.alpn_protocols - - # check with addons what we shall do - tls_clienthello = ClientHelloData(self.context, client_hello) - yield TlsClienthelloHook(tls_clienthello) - - # replace the QUIC layer with an UDP layer if requested - if tls_clienthello.ignore_connection: - self.conn = self.tunnel_connection = connection.Client( - peername=("ignore-conn", 0), - sockname=("ignore-conn", 0), - transport_protocol="udp", - state=connection.ConnectionState.OPEN, - ) - - # we need to replace the server layer as well, if there is one - parent_layer = self.context.layers[self.context.layers.index(self) - 1] - if isinstance(parent_layer, ServerQuicLayer): - parent_layer.conn = parent_layer.tunnel_connection = connection.Server( - address=None - ) - replacement_layer = UDPLayer(self.context, ignore=True) - parent_layer.handle_event = replacement_layer.handle_event # type: ignore - parent_layer._handle_event = replacement_layer._handle_event # type: ignore - yield from parent_layer.handle_event(events.Start()) - yield from parent_layer.handle_event( - events.DataReceived(self.context.client, data) - ) - return True, None - - # start the server QUIC connection if demanded and available - if ( - tls_clienthello.establish_server_tls_first - and not self.context.server.tls_established - ): - err = yield from self.start_server_tls() - if err: - yield commands.Log( - f"Unable to establish QUIC connection with server ({err}). " - f"Trying to establish QUIC with client anyway. " - f"If you plan to redirect requests away from this server, " - f"consider setting `connection_strategy` to `lazy` to suppress early connections." - ) - - # start the client QUIC connection - yield from self.start_tls(header.destination_cid) - # XXX copied from TLS, we assume that `CloseConnection` in `start_tls` takes effect immediately - if not self.conn.connected: - return False, "connection closed early" - - # send the client hello to aioquic - return (yield from super().receive_handshake_data(data)) - - def start_server_tls(self) -> layer.CommandGenerator[str | None]: - if not self.server_tls_available: - return f"No server QUIC available." - err = yield commands.OpenConnection(self.context.server) - return err - - def on_handshake_error(self, err: str) -> layer.CommandGenerator[None]: - yield commands.Log(f"Client QUIC handshake failed. {err}", level=WARNING) - yield from super().on_handshake_error(err) - self.event_to_child = self.errored # type: ignore - - def errored(self, event: events.Event) -> layer.CommandGenerator[None]: - if self.debug is not None: - yield commands.Log( - f"{self.debug}[quic] Swallowing {event} as handshake failed.", DEBUG - ) diff --git a/mitmproxy/proxy/layers/quic/__init__.py b/mitmproxy/proxy/layers/quic/__init__.py new file mode 100644 index 0000000000..28a3ce3be7 --- /dev/null +++ b/mitmproxy/proxy/layers/quic/__init__.py @@ -0,0 +1,41 @@ +from ._client_hello_parser import quic_parse_client_hello_from_datagrams +from ._commands import CloseQuicConnection +from ._commands import ResetQuicStream +from ._commands import SendQuicStreamData +from ._commands import StopSendingQuicStream +from ._events import QuicConnectionClosed +from ._events import QuicStreamDataReceived +from ._events import QuicStreamEvent +from ._events import QuicStreamReset +from ._events import QuicStreamStopSending +from ._hooks import QuicStartClientHook +from ._hooks import QuicStartServerHook +from ._hooks import QuicTlsData +from ._hooks import QuicTlsSettings +from ._raw_layers import QuicStreamLayer +from ._raw_layers import RawQuicLayer +from ._stream_layers import ClientQuicLayer +from ._stream_layers import error_code_to_str +from ._stream_layers import ServerQuicLayer + +__all__ = [ + "quic_parse_client_hello_from_datagrams", + "CloseQuicConnection", + "ResetQuicStream", + "SendQuicStreamData", + "StopSendingQuicStream", + "QuicConnectionClosed", + "QuicStreamDataReceived", + "QuicStreamEvent", + "QuicStreamReset", + "QuicStreamStopSending", + "QuicStartClientHook", + "QuicStartServerHook", + "QuicTlsData", + "QuicTlsSettings", + "QuicStreamLayer", + "RawQuicLayer", + "ClientQuicLayer", + "error_code_to_str", + "ServerQuicLayer", +] diff --git a/mitmproxy/proxy/layers/quic/_client_hello_parser.py b/mitmproxy/proxy/layers/quic/_client_hello_parser.py new file mode 100644 index 0000000000..46dd615084 --- /dev/null +++ b/mitmproxy/proxy/layers/quic/_client_hello_parser.py @@ -0,0 +1,111 @@ +""" +This module contains a very terrible QUIC client hello parser. + +Nothing is more permanent than a temporary solution! +""" + +from __future__ import annotations + +import time +from dataclasses import dataclass +from typing import Optional + +from aioquic.buffer import Buffer as QuicBuffer +from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.connection import QuicConnection +from aioquic.quic.connection import QuicConnectionError +from aioquic.quic.logger import QuicLogger +from aioquic.quic.packet import PACKET_TYPE_INITIAL +from aioquic.quic.packet import pull_quic_header +from aioquic.tls import HandshakeType + +from mitmproxy.tls import ClientHello + + +@dataclass +class QuicClientHello(Exception): + """Helper error only used in `quic_parse_client_hello_from_datagrams`.""" + + data: bytes + + +def quic_parse_client_hello_from_datagrams( + datagrams: list[bytes], +) -> Optional[ClientHello]: + """ + Check if the supplied bytes contain a full ClientHello message, + and if so, parse it. + + Args: + - msgs: list of ClientHello fragments received from client + + Returns: + - A ClientHello object on success + - None, if the QUIC record is incomplete + + Raises: + - A ValueError, if the passed ClientHello is invalid + """ + + # ensure the first packet is indeed the initial one + buffer = QuicBuffer(data=datagrams[0]) + header = pull_quic_header(buffer, 8) + if header.packet_type != PACKET_TYPE_INITIAL: + raise ValueError("Packet is not initial one.") + + # patch aioquic to intercept the client hello + quic = QuicConnection( + configuration=QuicConfiguration( + is_client=False, + certificate="", + private_key="", + quic_logger=QuicLogger(), + ), + original_destination_connection_id=header.destination_cid, + ) + _initialize = quic._initialize + + def server_handle_hello_replacement( + input_buf: QuicBuffer, + initial_buf: QuicBuffer, + handshake_buf: QuicBuffer, + onertt_buf: QuicBuffer, + ) -> None: + assert input_buf.pull_uint8() == HandshakeType.CLIENT_HELLO + length = 0 + for b in input_buf.pull_bytes(3): + length = (length << 8) | b + offset = input_buf.tell() + raise QuicClientHello(input_buf.data_slice(offset, offset + length)) + + def initialize_replacement(peer_cid: bytes) -> None: + try: + return _initialize(peer_cid) + finally: + quic.tls._server_handle_hello = server_handle_hello_replacement # type: ignore + + quic._initialize = initialize_replacement # type: ignore + try: + for dgm in datagrams: + quic.receive_datagram(dgm, ("0.0.0.0", 0), now=time.time()) + except QuicClientHello as hello: + try: + return ClientHello(hello.data) + except EOFError as e: + raise ValueError("Invalid ClientHello data.") from e + except QuicConnectionError as e: + raise ValueError(e.reason_phrase) from e + + quic_logger = quic._configuration.quic_logger + assert isinstance(quic_logger, QuicLogger) + traces = quic_logger.to_dict().get("traces") + assert isinstance(traces, list) + for trace in traces: + quic_events = trace.get("events") + for event in quic_events: + if event["name"] == "transport:packet_dropped": + raise ValueError( + f"Invalid ClientHello packet: {event['data']['trigger']}" + ) + + return None # pragma: no cover # FIXME: this should have test coverage diff --git a/mitmproxy/proxy/layers/quic/_commands.py b/mitmproxy/proxy/layers/quic/_commands.py new file mode 100644 index 0000000000..1f952c3c66 --- /dev/null +++ b/mitmproxy/proxy/layers/quic/_commands.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from mitmproxy import connection +from mitmproxy.proxy import commands + + +class QuicStreamCommand(commands.ConnectionCommand): + """Base class for all QUIC stream commands.""" + + stream_id: int + """The ID of the stream the command was issued for.""" + + def __init__(self, connection: connection.Connection, stream_id: int) -> None: + super().__init__(connection) + self.stream_id = stream_id + + +class SendQuicStreamData(QuicStreamCommand): + """Command that sends data on a stream.""" + + data: bytes + """The data which should be sent.""" + end_stream: bool + """Whether the FIN bit should be set in the STREAM frame.""" + + def __init__( + self, + connection: connection.Connection, + stream_id: int, + data: bytes, + end_stream: bool = False, + ) -> None: + super().__init__(connection, stream_id) + self.data = data + self.end_stream = end_stream + + def __repr__(self): + target = repr(self.connection).partition("(")[0].lower() + end_stream = "[end_stream] " if self.end_stream else "" + return f"SendQuicStreamData({target} on {self.stream_id}, {end_stream}{self.data!r})" + + +class ResetQuicStream(QuicStreamCommand): + """Abruptly terminate the sending part of a stream.""" + + error_code: int + """An error code indicating why the stream is being reset.""" + + def __init__( + self, connection: connection.Connection, stream_id: int, error_code: int + ) -> None: + super().__init__(connection, stream_id) + self.error_code = error_code + + +class StopSendingQuicStream(QuicStreamCommand): + """Request termination of the receiving part of a stream.""" + + error_code: int + """An error code indicating why the stream is being stopped.""" + + def __init__( + self, connection: connection.Connection, stream_id: int, error_code: int + ) -> None: + super().__init__(connection, stream_id) + self.error_code = error_code + + +class CloseQuicConnection(commands.CloseConnection): + """Close a QUIC connection.""" + + error_code: int + "The error code which was specified when closing the connection." + + frame_type: int | None + "The frame type which caused the connection to be closed, or `None`." + + reason_phrase: str + "The human-readable reason for which the connection was closed." + + # XXX: A bit much boilerplate right now. Should switch to dataclasses. + def __init__( + self, + conn: connection.Connection, + error_code: int, + frame_type: int | None, + reason_phrase: str, + ) -> None: + super().__init__(conn) + self.error_code = error_code + self.frame_type = frame_type + self.reason_phrase = reason_phrase diff --git a/mitmproxy/proxy/layers/quic/_events.py b/mitmproxy/proxy/layers/quic/_events.py new file mode 100644 index 0000000000..67a4d4a8e0 --- /dev/null +++ b/mitmproxy/proxy/layers/quic/_events.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from mitmproxy import connection +from mitmproxy.proxy import events + + +@dataclass +class QuicStreamEvent(events.ConnectionEvent): + """Base class for all QUIC stream events.""" + + stream_id: int + """The ID of the stream the event was fired for.""" + + +@dataclass +class QuicStreamDataReceived(QuicStreamEvent): + """Event that is fired whenever data is received on a stream.""" + + data: bytes + """The data which was received.""" + end_stream: bool + """Whether the STREAM frame had the FIN bit set.""" + + def __repr__(self): + target = repr(self.connection).partition("(")[0].lower() + end_stream = "[end_stream] " if self.end_stream else "" + return f"QuicStreamDataReceived({target} on {self.stream_id}, {end_stream}{self.data!r})" + + +@dataclass +class QuicStreamReset(QuicStreamEvent): + """Event that is fired when the remote peer resets a stream.""" + + error_code: int + """The error code that triggered the reset.""" + + +@dataclass +class QuicStreamStopSending(QuicStreamEvent): + """Event that is fired when the remote peer sends a STOP_SENDING frame.""" + + error_code: int + """The application protocol error code.""" + + +class QuicConnectionClosed(events.ConnectionClosed): + """QUIC connection has been closed.""" + + error_code: int + "The error code which was specified when closing the connection." + + frame_type: int | None + "The frame type which caused the connection to be closed, or `None`." + + reason_phrase: str + "The human-readable reason for which the connection was closed." + + def __init__( + self, + conn: connection.Connection, + error_code: int, + frame_type: int | None, + reason_phrase: str, + ) -> None: + super().__init__(conn) + self.error_code = error_code + self.frame_type = frame_type + self.reason_phrase = reason_phrase diff --git a/mitmproxy/proxy/layers/quic/_hooks.py b/mitmproxy/proxy/layers/quic/_hooks.py new file mode 100644 index 0000000000..9c84e74d52 --- /dev/null +++ b/mitmproxy/proxy/layers/quic/_hooks.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from dataclasses import dataclass +from dataclasses import field +from ssl import VerifyMode + +from aioquic.tls import CipherSuite +from cryptography import x509 +from cryptography.hazmat.primitives.asymmetric import dsa +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import rsa + +from mitmproxy.proxy import commands +from mitmproxy.tls import TlsData + + +@dataclass +class QuicTlsSettings: + """ + Settings necessary to establish QUIC's TLS context. + """ + + alpn_protocols: list[str] | None = None + """A list of supported ALPN protocols.""" + certificate: x509.Certificate | None = None + """The certificate to use for the connection.""" + certificate_chain: list[x509.Certificate] = field(default_factory=list) + """A list of additional certificates to send to the peer.""" + certificate_private_key: ( + dsa.DSAPrivateKey | ec.EllipticCurvePrivateKey | rsa.RSAPrivateKey | None + ) = None + """The certificate's private key.""" + cipher_suites: list[CipherSuite] | None = None + """An optional list of allowed/advertised cipher suites.""" + ca_path: str | None = None + """An optional path to a directory that contains the necessary information to verify the peer certificate.""" + ca_file: str | None = None + """An optional path to a PEM file that will be used to verify the peer certificate.""" + verify_mode: VerifyMode | None = None + """An optional flag that specifies how/if the peer's certificate should be validated.""" + + +@dataclass +class QuicTlsData(TlsData): + """ + Event data for `quic_start_client` and `quic_start_server` event hooks. + """ + + settings: QuicTlsSettings | None = None + """ + The associated `QuicTlsSettings` object. + This will be set by an addon in the `quic_start_*` event hooks. + """ + + +@dataclass +class QuicStartClientHook(commands.StartHook): + """ + TLS negotiation between mitmproxy and a client over QUIC is about to start. + + An addon is expected to initialize data.settings. + (by default, this is done by `mitmproxy.addons.tlsconfig`) + """ + + data: QuicTlsData + + +@dataclass +class QuicStartServerHook(commands.StartHook): + """ + TLS negotiation between mitmproxy and a server over QUIC is about to start. + + An addon is expected to initialize data.settings. + (by default, this is done by `mitmproxy.addons.tlsconfig`) + """ + + data: QuicTlsData diff --git a/mitmproxy/proxy/layers/quic/_raw_layers.py b/mitmproxy/proxy/layers/quic/_raw_layers.py new file mode 100644 index 0000000000..18d1a367a1 --- /dev/null +++ b/mitmproxy/proxy/layers/quic/_raw_layers.py @@ -0,0 +1,430 @@ +""" +This module contains the proxy layers for raw QUIC proxying. +This is used if we want to speak QUIC, but we do not want to do HTTP. +""" + +from __future__ import annotations + +import time + +from aioquic.quic.connection import QuicErrorCode +from aioquic.quic.connection import stream_is_client_initiated +from aioquic.quic.connection import stream_is_unidirectional + +from ._commands import CloseQuicConnection +from ._commands import ResetQuicStream +from ._commands import SendQuicStreamData +from ._commands import StopSendingQuicStream +from ._events import QuicConnectionClosed +from ._events import QuicStreamDataReceived +from ._events import QuicStreamEvent +from ._events import QuicStreamReset +from mitmproxy import connection +from mitmproxy.proxy import commands +from mitmproxy.proxy import context +from mitmproxy.proxy import events +from mitmproxy.proxy import layer +from mitmproxy.proxy import tunnel +from mitmproxy.proxy.layers.tcp import TCPLayer +from mitmproxy.proxy.layers.udp import UDPLayer + + +class QuicStreamNextLayer(layer.NextLayer): + """`NextLayer` variant that callbacks `QuicStreamLayer` after layer decision.""" + + def __init__( + self, + context: context.Context, + stream: QuicStreamLayer, + ask_on_start: bool = False, + ) -> None: + super().__init__(context, ask_on_start) + self._stream = stream + self._layer: layer.Layer | None = None + + @property # type: ignore + def layer(self) -> layer.Layer | None: # type: ignore + return self._layer + + @layer.setter + def layer(self, value: layer.Layer | None) -> None: + self._layer = value + if self._layer: + self._stream.refresh_metadata() + + +class QuicStreamLayer(layer.Layer): + """ + Layer for QUIC streams. + Serves as a marker for NextLayer and keeps track of the connection states. + """ + + client: connection.Client + """Virtual client connection for this stream. Use this in QuicRawLayer instead of `context.client`.""" + server: connection.Server + """Virtual server connection for this stream. Use this in QuicRawLayer instead of `context.server`.""" + child_layer: layer.Layer + """The stream's child layer.""" + + def __init__( + self, context: context.Context, force_raw: bool, stream_id: int + ) -> None: + # we mustn't reuse the client from the QUIC connection, as the state and protocol differs + self.client = context.client = context.client.copy() + self.client.transport_protocol = "tcp" + self.client.state = connection.ConnectionState.OPEN + + # unidirectional client streams are not fully open, set the appropriate state + if stream_is_unidirectional(stream_id): + self.client.state = ( + connection.ConnectionState.CAN_READ + if stream_is_client_initiated(stream_id) + else connection.ConnectionState.CAN_WRITE + ) + self._client_stream_id = stream_id + + # start with a closed server + self.server = context.server = connection.Server( + address=context.server.address, + transport_protocol="tcp", + ) + self._server_stream_id: int | None = None + + super().__init__(context) + self.child_layer = ( + TCPLayer(context) if force_raw else QuicStreamNextLayer(context, self) + ) + self.refresh_metadata() + + # we don't handle any events, pass everything to the child layer + self.handle_event = self.child_layer.handle_event # type: ignore + self._handle_event = self.child_layer._handle_event # type: ignore + + def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: + raise AssertionError # pragma: no cover + + def open_server_stream(self, server_stream_id) -> None: + assert self._server_stream_id is None + self._server_stream_id = server_stream_id + self.server.timestamp_start = time.time() + self.server.state = ( + ( + connection.ConnectionState.CAN_WRITE + if stream_is_client_initiated(server_stream_id) + else connection.ConnectionState.CAN_READ + ) + if stream_is_unidirectional(server_stream_id) + else connection.ConnectionState.OPEN + ) + self.refresh_metadata() + + def refresh_metadata(self) -> None: + # find the first transport layer + child_layer: layer.Layer | None = self.child_layer + while True: + if isinstance(child_layer, layer.NextLayer): + child_layer = child_layer.layer + elif isinstance(child_layer, tunnel.TunnelLayer): + child_layer = child_layer.child_layer + else: + break # pragma: no cover + if isinstance(child_layer, (UDPLayer, TCPLayer)) and child_layer.flow: + child_layer.flow.metadata["quic_is_unidirectional"] = ( + stream_is_unidirectional(self._client_stream_id) + ) + child_layer.flow.metadata["quic_initiator"] = ( + "client" + if stream_is_client_initiated(self._client_stream_id) + else "server" + ) + child_layer.flow.metadata["quic_stream_id_client"] = self._client_stream_id + child_layer.flow.metadata["quic_stream_id_server"] = self._server_stream_id + + def stream_id(self, client: bool) -> int | None: + return self._client_stream_id if client else self._server_stream_id + + +class RawQuicLayer(layer.Layer): + """ + This layer is responsible for de-multiplexing QUIC streams into an individual layer stack per stream. + """ + + force_raw: bool + """Indicates whether traffic should be treated as raw TCP/UDP without further protocol detection.""" + datagram_layer: layer.Layer + """ + The layer that is handling datagrams over QUIC. It's like a child_layer, but with a forked context. + Instead of having a datagram-equivalent for all `QuicStream*` classes, we use `SendData` and `DataReceived` instead. + There is also no need for another `NextLayer` marker, as a missing `QuicStreamLayer` implies UDP, + and the connection state is the same as the one of the underlying QUIC connection. + """ + client_stream_ids: dict[int, QuicStreamLayer] + """Maps stream IDs from the client connection to stream layers.""" + server_stream_ids: dict[int, QuicStreamLayer] + """Maps stream IDs from the server connection to stream layers.""" + connections: dict[connection.Connection, layer.Layer] + """Maps connections to layers.""" + command_sources: dict[commands.Command, layer.Layer] + """Keeps track of blocking commands and wakeup requests.""" + next_stream_id: list[int] + """List containing the next stream ID for all four is_unidirectional/is_client combinations.""" + + def __init__(self, context: context.Context, force_raw: bool = False) -> None: + super().__init__(context) + self.force_raw = force_raw + self.datagram_layer = ( + UDPLayer(self.context.fork()) + if force_raw + else layer.NextLayer(self.context.fork()) + ) + self.client_stream_ids = {} + self.server_stream_ids = {} + self.connections = { + context.client: self.datagram_layer, + context.server: self.datagram_layer, + } + self.command_sources = {} + self.next_stream_id = [0, 1, 2, 3] + + def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: + # we treat the datagram layer as child layer, so forward Start + if isinstance(event, events.Start): + if self.context.server.timestamp_start is None: + err = yield commands.OpenConnection(self.context.server) + if err: + yield commands.CloseConnection(self.context.client) + self._handle_event = self.done # type: ignore + return + yield from self.event_to_child(self.datagram_layer, event) + + # properly forward completion events based on their command + elif isinstance(event, events.CommandCompleted): + yield from self.event_to_child( + self.command_sources.pop(event.command), event + ) + + # route injected messages based on their connections (prefer client, fallback to server) + elif isinstance(event, events.MessageInjected): + if event.flow.client_conn in self.connections: + yield from self.event_to_child( + self.connections[event.flow.client_conn], event + ) + elif event.flow.server_conn in self.connections: + yield from self.event_to_child( + self.connections[event.flow.server_conn], event + ) + else: + raise AssertionError(f"Flow not associated: {event.flow!r}") + + # handle stream events targeting this context + elif isinstance(event, QuicStreamEvent) and ( + event.connection is self.context.client + or event.connection is self.context.server + ): + from_client = event.connection is self.context.client + + # fetch or create the layer + stream_ids = ( + self.client_stream_ids if from_client else self.server_stream_ids + ) + if event.stream_id in stream_ids: + stream_layer = stream_ids[event.stream_id] + else: + # ensure we haven't just forgotten to register the ID + assert stream_is_client_initiated(event.stream_id) == from_client + + # for server-initiated streams we need to open the client as well + if from_client: + client_stream_id = event.stream_id + server_stream_id = None + else: + client_stream_id = self.get_next_available_stream_id( + is_client=False, + is_unidirectional=stream_is_unidirectional(event.stream_id), + ) + server_stream_id = event.stream_id + + # create, register and start the layer + stream_layer = QuicStreamLayer( + self.context.fork(), + force_raw=self.force_raw, + stream_id=client_stream_id, + ) + self.client_stream_ids[client_stream_id] = stream_layer + if server_stream_id is not None: + stream_layer.open_server_stream(server_stream_id) + self.server_stream_ids[server_stream_id] = stream_layer + self.connections[stream_layer.client] = stream_layer + self.connections[stream_layer.server] = stream_layer + yield from self.event_to_child(stream_layer, events.Start()) + + # forward data and close events + conn = stream_layer.client if from_client else stream_layer.server + if isinstance(event, QuicStreamDataReceived): + if event.data: + yield from self.event_to_child( + stream_layer, events.DataReceived(conn, event.data) + ) + if event.end_stream: + yield from self.close_stream_layer(stream_layer, from_client) + elif isinstance(event, QuicStreamReset): + # preserve stream resets + for command in self.close_stream_layer(stream_layer, from_client): + if ( + isinstance(command, SendQuicStreamData) + and command.stream_id == stream_layer.stream_id(not from_client) + and command.end_stream + and not command.data + ): + yield ResetQuicStream( + command.connection, command.stream_id, event.error_code + ) + else: + yield command + else: + raise AssertionError(f"Unexpected stream event: {event!r}") + + # handle close events that target this context + elif isinstance(event, QuicConnectionClosed) and ( + event.connection is self.context.client + or event.connection is self.context.server + ): + from_client = event.connection is self.context.client + other_conn = self.context.server if from_client else self.context.client + + # be done if both connections are closed + if other_conn.connected: + yield CloseQuicConnection( + other_conn, event.error_code, event.frame_type, event.reason_phrase + ) + else: + self._handle_event = self.done # type: ignore + + # always forward to the datagram layer and swallow `CloseConnection` commands + for command in self.event_to_child(self.datagram_layer, event): + if ( + not isinstance(command, commands.CloseConnection) + or command.connection is not other_conn + ): + yield command + + # forward to either the client or server connection of stream layers and swallow empty stream end + for conn, child_layer in self.connections.items(): + if isinstance(child_layer, QuicStreamLayer) and ( + (conn is child_layer.client) + if from_client + else (conn is child_layer.server) + ): + conn.state &= ~connection.ConnectionState.CAN_WRITE + for command in self.close_stream_layer(child_layer, from_client): + if not isinstance(command, SendQuicStreamData) or command.data: + yield command + + # all other connection events are routed to their corresponding layer + elif isinstance(event, events.ConnectionEvent): + yield from self.event_to_child(self.connections[event.connection], event) + + else: + raise AssertionError(f"Unexpected event: {event!r}") + + def close_stream_layer( + self, stream_layer: QuicStreamLayer, client: bool + ) -> layer.CommandGenerator[None]: + """Closes the incoming part of a connection.""" + + conn = stream_layer.client if client else stream_layer.server + conn.state &= ~connection.ConnectionState.CAN_READ + assert conn.timestamp_start is not None + if conn.timestamp_end is None: + conn.timestamp_end = time.time() + yield from self.event_to_child(stream_layer, events.ConnectionClosed(conn)) + + def event_to_child( + self, child_layer: layer.Layer, event: events.Event + ) -> layer.CommandGenerator[None]: + """Forwards events to child layers and translates commands.""" + + for command in child_layer.handle_event(event): + # intercept commands for streams connections + if ( + isinstance(child_layer, QuicStreamLayer) + and isinstance(command, commands.ConnectionCommand) + and ( + command.connection is child_layer.client + or command.connection is child_layer.server + ) + ): + # get the target connection and stream ID + to_client = command.connection is child_layer.client + quic_conn = self.context.client if to_client else self.context.server + stream_id = child_layer.stream_id(to_client) + + # write data and check CloseConnection wasn't called before + if isinstance(command, commands.SendData): + assert stream_id is not None + if command.connection.state & connection.ConnectionState.CAN_WRITE: + yield SendQuicStreamData(quic_conn, stream_id, command.data) + + # send a FIN and optionally also a STOP frame + elif isinstance(command, commands.CloseConnection): + assert stream_id is not None + if command.connection.state & connection.ConnectionState.CAN_WRITE: + command.connection.state &= ( + ~connection.ConnectionState.CAN_WRITE + ) + yield SendQuicStreamData( + quic_conn, stream_id, b"", end_stream=True + ) + # XXX: Use `command.connection.state & connection.ConnectionState.CAN_READ` instead? + only_close_our_half = ( + isinstance(command, commands.CloseTcpConnection) + and command.half_close + ) + if not only_close_our_half: + if stream_is_client_initiated( + stream_id + ) == to_client or not stream_is_unidirectional(stream_id): + yield StopSendingQuicStream( + quic_conn, stream_id, QuicErrorCode.NO_ERROR + ) + yield from self.close_stream_layer(child_layer, to_client) + + # open server connections by reserving the next stream ID + elif isinstance(command, commands.OpenConnection): + assert not to_client + assert stream_id is None + client_stream_id = child_layer.stream_id(client=True) + assert client_stream_id is not None + stream_id = self.get_next_available_stream_id( + is_client=True, + is_unidirectional=stream_is_unidirectional(client_stream_id), + ) + child_layer.open_server_stream(stream_id) + self.server_stream_ids[stream_id] = child_layer + yield from self.event_to_child( + child_layer, events.OpenConnectionCompleted(command, None) + ) + + else: + raise AssertionError( + f"Unexpected stream connection command: {command!r}" + ) + + # remember blocking and wakeup commands + else: + if command.blocking or isinstance(command, commands.RequestWakeup): + self.command_sources[command] = child_layer + if isinstance(command, commands.OpenConnection): + self.connections[command.connection] = child_layer + yield command + + def get_next_available_stream_id( + self, is_client: bool, is_unidirectional: bool = False + ) -> int: + index = (int(is_unidirectional) << 1) | int(not is_client) + stream_id = self.next_stream_id[index] + self.next_stream_id[index] = stream_id + 4 + return stream_id + + def done(self, _) -> layer.CommandGenerator[None]: # pragma: no cover + yield from () diff --git a/mitmproxy/proxy/layers/quic/_stream_layers.py b/mitmproxy/proxy/layers/quic/_stream_layers.py new file mode 100644 index 0000000000..3f460dc44f --- /dev/null +++ b/mitmproxy/proxy/layers/quic/_stream_layers.py @@ -0,0 +1,638 @@ +""" +This module contains the client and server proxy layers for QUIC streams +which decrypt and encrypt traffic. Decrypted stream data is then forwarded +to either the raw layers, or the HTTP/3 client in ../http/_http3.py. +""" + +from __future__ import annotations + +import time +from collections.abc import Callable +from logging import DEBUG +from logging import ERROR +from logging import WARNING + +from aioquic.buffer import Buffer as QuicBuffer +from aioquic.h3.connection import ErrorCode as H3ErrorCode +from aioquic.quic import events as quic_events +from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.connection import QuicConnection +from aioquic.quic.connection import QuicConnectionState +from aioquic.quic.connection import QuicErrorCode +from aioquic.quic.packet import encode_quic_version_negotiation +from aioquic.quic.packet import PACKET_TYPE_INITIAL +from aioquic.quic.packet import pull_quic_header +from cryptography import x509 + +from ._client_hello_parser import quic_parse_client_hello_from_datagrams +from ._commands import CloseQuicConnection +from ._commands import QuicStreamCommand +from ._commands import ResetQuicStream +from ._commands import SendQuicStreamData +from ._commands import StopSendingQuicStream +from ._events import QuicConnectionClosed +from ._events import QuicStreamDataReceived +from ._events import QuicStreamReset +from ._events import QuicStreamStopSending +from ._hooks import QuicStartClientHook +from ._hooks import QuicStartServerHook +from ._hooks import QuicTlsData +from ._hooks import QuicTlsSettings +from mitmproxy import certs +from mitmproxy import connection +from mitmproxy import ctx +from mitmproxy.net import tls +from mitmproxy.proxy import commands +from mitmproxy.proxy import context +from mitmproxy.proxy import events +from mitmproxy.proxy import layer +from mitmproxy.proxy import tunnel +from mitmproxy.proxy.layers.tls import TlsClienthelloHook +from mitmproxy.proxy.layers.tls import TlsEstablishedClientHook +from mitmproxy.proxy.layers.tls import TlsEstablishedServerHook +from mitmproxy.proxy.layers.tls import TlsFailedClientHook +from mitmproxy.proxy.layers.tls import TlsFailedServerHook +from mitmproxy.proxy.layers.udp import UDPLayer +from mitmproxy.tls import ClientHelloData + +SUPPORTED_QUIC_VERSIONS_SERVER = QuicConfiguration(is_client=False).supported_versions + + +class QuicLayer(tunnel.TunnelLayer): + quic: QuicConnection | None = None + tls: QuicTlsSettings | None = None + + def __init__( + self, + context: context.Context, + conn: connection.Connection, + time: Callable[[], float] | None, + ) -> None: + super().__init__(context, tunnel_connection=conn, conn=conn) + self.child_layer = layer.NextLayer(self.context, ask_on_start=True) + self._time = time or ctx.master.event_loop.time + self._wakeup_commands: dict[commands.RequestWakeup, float] = dict() + conn.tls = True + + def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: + if isinstance(event, events.Wakeup) and event.command in self._wakeup_commands: + # TunnelLayer has no understanding of wakeups, so we turn this into an empty DataReceived event + # which TunnelLayer recognizes as belonging to our connection. + assert self.quic + scheduled_time = self._wakeup_commands.pop(event.command) + if self.quic._state is not QuicConnectionState.TERMINATED: + # weird quirk: asyncio sometimes returns a bit ahead of time. + now = max(scheduled_time, self._time()) + self.quic.handle_timer(now) + yield from super()._handle_event( + events.DataReceived(self.tunnel_connection, b"") + ) + else: + yield from super()._handle_event(event) + + def event_to_child(self, event: events.Event) -> layer.CommandGenerator[None]: + # the parent will call _handle_command multiple times, we transmit cumulative afterwards + # this will reduce the number of sends, especially if data=b"" and end_stream=True + yield from super().event_to_child(event) + if self.quic: + yield from self.tls_interact() + + def _handle_command( + self, command: commands.Command + ) -> layer.CommandGenerator[None]: + """Turns stream commands into aioquic connection invocations.""" + if isinstance(command, QuicStreamCommand) and command.connection is self.conn: + assert self.quic + if isinstance(command, SendQuicStreamData): + self.quic.send_stream_data( + command.stream_id, command.data, command.end_stream + ) + elif isinstance(command, ResetQuicStream): + stream = self.quic._get_or_create_stream_for_send(command.stream_id) + existing_reset_error_code = stream.sender._reset_error_code + if existing_reset_error_code is None: + self.quic.reset_stream(command.stream_id, command.error_code) + elif self.debug: # pragma: no cover + yield commands.Log( + f"{self.debug}[quic] stream {stream.stream_id} already reset ({existing_reset_error_code=}, {command.error_code=})", + DEBUG, + ) + elif isinstance(command, StopSendingQuicStream): + # the stream might have already been closed, check before stopping + if command.stream_id in self.quic._streams: + self.quic.stop_stream(command.stream_id, command.error_code) + else: + raise AssertionError(f"Unexpected stream command: {command!r}") + else: + yield from super()._handle_command(command) + + def start_tls( + self, original_destination_connection_id: bytes | None + ) -> layer.CommandGenerator[None]: + """Initiates the aioquic connection.""" + + # must only be called if QUIC is uninitialized + assert not self.quic + assert not self.tls + + # query addons to provide the necessary TLS settings + tls_data = QuicTlsData(self.conn, self.context) + if self.conn is self.context.client: + yield QuicStartClientHook(tls_data) + else: + yield QuicStartServerHook(tls_data) + if not tls_data.settings: + yield commands.Log( + f"No QUIC context was provided, failing connection.", ERROR + ) + yield commands.CloseConnection(self.conn) + return + + # build the aioquic connection + configuration = tls_settings_to_configuration( + settings=tls_data.settings, + is_client=self.conn is self.context.server, + server_name=self.conn.sni, + ) + self.quic = QuicConnection( + configuration=configuration, + original_destination_connection_id=original_destination_connection_id, + ) + self.tls = tls_data.settings + + # if we act as client, connect to upstream + if original_destination_connection_id is None: + self.quic.connect(self.conn.peername, now=self._time()) + yield from self.tls_interact() + + def tls_interact(self) -> layer.CommandGenerator[None]: + """Retrieves all pending outgoing packets from aioquic and sends the data.""" + + # send all queued datagrams + assert self.quic + now = self._time() + + for data, addr in self.quic.datagrams_to_send(now=now): + assert addr == self.conn.peername + yield commands.SendData(self.tunnel_connection, data) + + timer = self.quic.get_timer() + if timer is not None: + # smooth wakeups a bit. + smoothed = timer + 0.002 + # request a new wakeup if all pending requests trigger at a later time + if not any( + existing <= smoothed for existing in self._wakeup_commands.values() + ): + command = commands.RequestWakeup(timer - now) + self._wakeup_commands[command] = timer + yield command + + def receive_handshake_data( + self, data: bytes + ) -> layer.CommandGenerator[tuple[bool, str | None]]: + assert self.quic + + # forward incoming data to aioquic + if data: + self.quic.receive_datagram(data, self.conn.peername, now=self._time()) + + # handle pre-handshake events + while event := self.quic.next_event(): + if isinstance(event, quic_events.ConnectionTerminated): + err = event.reason_phrase or error_code_to_str(event.error_code) + return False, err + elif isinstance(event, quic_events.HandshakeCompleted): + # concatenate all peer certificates + all_certs: list[x509.Certificate] = [] + if self.quic.tls._peer_certificate: + all_certs.append(self.quic.tls._peer_certificate) + all_certs.extend(self.quic.tls._peer_certificate_chain) + + # set the connection's TLS properties + self.conn.timestamp_tls_setup = time.time() + if event.alpn_protocol: + self.conn.alpn = event.alpn_protocol.encode("ascii") + self.conn.certificate_list = [certs.Cert(cert) for cert in all_certs] + assert self.quic.tls.key_schedule + self.conn.cipher = self.quic.tls.key_schedule.cipher_suite.name + self.conn.tls_version = "QUICv1" + + # log the result and report the success to addons + if self.debug: + yield commands.Log( + f"{self.debug}[quic] tls established: {self.conn}", DEBUG + ) + if self.conn is self.context.client: + yield TlsEstablishedClientHook( + QuicTlsData(self.conn, self.context, settings=self.tls) + ) + else: + yield TlsEstablishedServerHook( + QuicTlsData(self.conn, self.context, settings=self.tls) + ) + + yield from self.tls_interact() + return True, None + elif isinstance( + event, + ( + quic_events.ConnectionIdIssued, + quic_events.ConnectionIdRetired, + quic_events.PingAcknowledged, + quic_events.ProtocolNegotiated, + ), + ): + pass + else: + raise AssertionError(f"Unexpected event: {event!r}") + + # transmit buffered data and re-arm timer + yield from self.tls_interact() + return False, None + + def on_handshake_error(self, err: str) -> layer.CommandGenerator[None]: + self.conn.error = err + if self.conn is self.context.client: + yield TlsFailedClientHook( + QuicTlsData(self.conn, self.context, settings=self.tls) + ) + else: + yield TlsFailedServerHook( + QuicTlsData(self.conn, self.context, settings=self.tls) + ) + yield from super().on_handshake_error(err) + + def receive_data(self, data: bytes) -> layer.CommandGenerator[None]: + assert self.quic + + # forward incoming data to aioquic + if data: + self.quic.receive_datagram(data, self.conn.peername, now=self._time()) + + # handle post-handshake events + while event := self.quic.next_event(): + if isinstance(event, quic_events.ConnectionTerminated): + if self.debug: + reason = event.reason_phrase or error_code_to_str(event.error_code) + yield commands.Log( + f"{self.debug}[quic] close_notify {self.conn} (reason={reason})", + DEBUG, + ) + # We don't rely on `ConnectionTerminated` to dispatch `QuicConnectionClosed`, because + # after aioquic receives a termination frame, it still waits for the next `handle_timer` + # before returning `ConnectionTerminated` in `next_event`. In the meantime, the underlying + # connection could be closed. Therefore, we instead dispatch on `ConnectionClosed` and simply + # close the connection here. + yield commands.CloseConnection(self.tunnel_connection) + return # we don't handle any further events, nor do/can we transmit data, so exit + elif isinstance(event, quic_events.DatagramFrameReceived): + yield from self.event_to_child( + events.DataReceived(self.conn, event.data) + ) + elif isinstance(event, quic_events.StreamDataReceived): + yield from self.event_to_child( + QuicStreamDataReceived( + self.conn, event.stream_id, event.data, event.end_stream + ) + ) + elif isinstance(event, quic_events.StreamReset): + yield from self.event_to_child( + QuicStreamReset(self.conn, event.stream_id, event.error_code) + ) + elif isinstance(event, quic_events.StopSendingReceived): + yield from self.event_to_child( + QuicStreamStopSending(self.conn, event.stream_id, event.error_code) + ) + elif isinstance( + event, + ( + quic_events.ConnectionIdIssued, + quic_events.ConnectionIdRetired, + quic_events.PingAcknowledged, + quic_events.ProtocolNegotiated, + ), + ): + pass + else: + raise AssertionError(f"Unexpected event: {event!r}") + + # transmit buffered data and re-arm timer + yield from self.tls_interact() + + def receive_close(self) -> layer.CommandGenerator[None]: + assert self.quic + # if `_close_event` is not set, the underlying connection has been closed + # we turn this into a QUIC close event as well + close_event = self.quic._close_event or quic_events.ConnectionTerminated( + QuicErrorCode.NO_ERROR, None, "Connection closed." + ) + yield from self.event_to_child( + QuicConnectionClosed( + self.conn, + close_event.error_code, + close_event.frame_type, + close_event.reason_phrase, + ) + ) + + def send_data(self, data: bytes) -> layer.CommandGenerator[None]: + # non-stream data uses datagram frames + assert self.quic + if data: + self.quic.send_datagram_frame(data) + yield from self.tls_interact() + + def send_close( + self, command: commands.CloseConnection + ) -> layer.CommandGenerator[None]: + # properly close the QUIC connection + if self.quic: + if isinstance(command, CloseQuicConnection): + self.quic.close( + command.error_code, command.frame_type, command.reason_phrase + ) + else: + self.quic.close() + yield from self.tls_interact() + yield from super().send_close(command) + + +class ServerQuicLayer(QuicLayer): + """ + This layer establishes QUIC for a single server connection. + """ + + wait_for_clienthello: bool = False + + def __init__( + self, + context: context.Context, + conn: connection.Server | None = None, + time: Callable[[], float] | None = None, + ): + super().__init__(context, conn or context.server, time) + + def start_handshake(self) -> layer.CommandGenerator[None]: + wait_for_clienthello = not self.command_to_reply_to and isinstance( + self.child_layer, ClientQuicLayer + ) + if wait_for_clienthello: + self.wait_for_clienthello = True + self.tunnel_state = tunnel.TunnelState.CLOSED + else: + yield from self.start_tls(None) + + def event_to_child(self, event: events.Event) -> layer.CommandGenerator[None]: + if self.wait_for_clienthello: + for command in super().event_to_child(event): + if ( + isinstance(command, commands.OpenConnection) + and command.connection == self.conn + ): + self.wait_for_clienthello = False + else: + yield command + else: + yield from super().event_to_child(event) + + def on_handshake_error(self, err: str) -> layer.CommandGenerator[None]: + yield commands.Log(f"Server QUIC handshake failed. {err}", level=WARNING) + yield from super().on_handshake_error(err) + + +class ClientQuicLayer(QuicLayer): + """ + This layer establishes QUIC on a single client connection. + """ + + server_tls_available: bool + """Indicates whether the parent layer is a ServerQuicLayer.""" + handshake_datagram_buf: list[bytes] + + def __init__( + self, context: context.Context, time: Callable[[], float] | None = None + ) -> None: + # same as ClientTLSLayer, we might be nested in some other transport + if context.client.tls: + context.client.alpn = None + context.client.cipher = None + context.client.sni = None + context.client.timestamp_tls_setup = None + context.client.tls_version = None + context.client.certificate_list = [] + context.client.mitmcert = None + context.client.alpn_offers = [] + context.client.cipher_list = [] + + super().__init__(context, context.client, time) + self.server_tls_available = len(self.context.layers) >= 2 and isinstance( + self.context.layers[-2], ServerQuicLayer + ) + self.handshake_datagram_buf = [] + + def start_handshake(self) -> layer.CommandGenerator[None]: + yield from () + + def receive_handshake_data( + self, data: bytes + ) -> layer.CommandGenerator[tuple[bool, str | None]]: + if not self.context.options.http3: + yield commands.Log( + f"Swallowing QUIC handshake because HTTP/3 is disabled.", DEBUG + ) + return False, None + + # if we already had a valid client hello, don't process further packets + if self.tls: + return (yield from super().receive_handshake_data(data)) + + # fail if the received data is not a QUIC packet + buffer = QuicBuffer(data=data) + try: + header = pull_quic_header(buffer) + except TypeError: + return False, f"Cannot parse QUIC header: Malformed head ({data.hex()})" + except ValueError as e: + return False, f"Cannot parse QUIC header: {e} ({data.hex()})" + + # negotiate version, support all versions known to aioquic + if ( + header.version is not None + and header.version not in SUPPORTED_QUIC_VERSIONS_SERVER + ): + yield commands.SendData( + self.tunnel_connection, + encode_quic_version_negotiation( + source_cid=header.destination_cid, + destination_cid=header.source_cid, + supported_versions=SUPPORTED_QUIC_VERSIONS_SERVER, + ), + ) + return False, None + + # ensure it's (likely) a client handshake packet + if len(data) < 1200 or header.packet_type != PACKET_TYPE_INITIAL: + return ( + False, + f"Invalid handshake received, roaming not supported. ({data.hex()})", + ) + + self.handshake_datagram_buf.append(data) + # extract the client hello + try: + client_hello = quic_parse_client_hello_from_datagrams( + self.handshake_datagram_buf + ) + except ValueError as e: + msgs = b"\n".join(self.handshake_datagram_buf) + dbg = f"Cannot parse ClientHello: {str(e)} ({msgs.hex()})" + self.handshake_datagram_buf.clear() + return False, dbg + + if not client_hello: + return False, None + + # copy the client hello information + self.conn.sni = client_hello.sni + self.conn.alpn_offers = client_hello.alpn_protocols + + # check with addons what we shall do + tls_clienthello = ClientHelloData(self.context, client_hello) + yield TlsClienthelloHook(tls_clienthello) + + # replace the QUIC layer with an UDP layer if requested + if tls_clienthello.ignore_connection: + self.conn = self.tunnel_connection = connection.Client( + peername=("ignore-conn", 0), + sockname=("ignore-conn", 0), + transport_protocol="udp", + state=connection.ConnectionState.OPEN, + ) + + # we need to replace the server layer as well, if there is one + parent_layer = self.context.layers[self.context.layers.index(self) - 1] + if isinstance(parent_layer, ServerQuicLayer): + parent_layer.conn = parent_layer.tunnel_connection = connection.Server( + address=None + ) + replacement_layer = UDPLayer(self.context, ignore=True) + parent_layer.handle_event = replacement_layer.handle_event # type: ignore + parent_layer._handle_event = replacement_layer._handle_event # type: ignore + yield from parent_layer.handle_event(events.Start()) + for dgm in self.handshake_datagram_buf: + yield from parent_layer.handle_event( + events.DataReceived(self.context.client, dgm) + ) + self.handshake_datagram_buf.clear() + return True, None + + # start the server QUIC connection if demanded and available + if ( + tls_clienthello.establish_server_tls_first + and not self.context.server.tls_established + ): + err = yield from self.start_server_tls() + if err: + yield commands.Log( + f"Unable to establish QUIC connection with server ({err}). " + f"Trying to establish QUIC with client anyway. " + f"If you plan to redirect requests away from this server, " + f"consider setting `connection_strategy` to `lazy` to suppress early connections." + ) + + # start the client QUIC connection + yield from self.start_tls(header.destination_cid) + # XXX copied from TLS, we assume that `CloseConnection` in `start_tls` takes effect immediately + if not self.conn.connected: + return False, "connection closed early" + + # send the client hello to aioquic + assert self.quic + for dgm in self.handshake_datagram_buf: + self.quic.receive_datagram(dgm, self.conn.peername, now=self._time()) + self.handshake_datagram_buf.clear() + + # handle events emanating from `self.quic` + return (yield from super().receive_handshake_data(b"")) + + def start_server_tls(self) -> layer.CommandGenerator[str | None]: + if not self.server_tls_available: + return f"No server QUIC available." + err = yield commands.OpenConnection(self.context.server) + return err + + def on_handshake_error(self, err: str) -> layer.CommandGenerator[None]: + yield commands.Log(f"Client QUIC handshake failed. {err}", level=WARNING) + yield from super().on_handshake_error(err) + self.event_to_child = self.errored # type: ignore + + def errored(self, event: events.Event) -> layer.CommandGenerator[None]: + if self.debug is not None: + yield commands.Log( + f"{self.debug}[quic] Swallowing {event} as handshake failed.", DEBUG + ) + + +class QuicSecretsLogger: + logger: tls.MasterSecretLogger + + def __init__(self, logger: tls.MasterSecretLogger) -> None: + super().__init__() + self.logger = logger + + def write(self, s: str) -> int: + if s[-1:] == "\n": + s = s[:-1] + data = s.encode("ascii") + self.logger(None, data) # type: ignore + return len(data) + 1 + + def flush(self) -> None: + # done by the logger during write + pass + + +def error_code_to_str(error_code: int) -> str: + """Returns the corresponding name of the given error code or a string containing its numeric value.""" + + try: + return H3ErrorCode(error_code).name + except ValueError: + try: + return QuicErrorCode(error_code).name + except ValueError: + return f"unknown error (0x{error_code:x})" + + +def is_success_error_code(error_code: int) -> bool: + """Returns whether the given error code actually indicates no error.""" + + return error_code in (QuicErrorCode.NO_ERROR, H3ErrorCode.H3_NO_ERROR) + + +def tls_settings_to_configuration( + settings: QuicTlsSettings, + is_client: bool, + server_name: str | None = None, +) -> QuicConfiguration: + """Converts `QuicTlsSettings` to `QuicConfiguration`.""" + + return QuicConfiguration( + alpn_protocols=settings.alpn_protocols, + is_client=is_client, + secrets_log_file=( + QuicSecretsLogger(tls.log_master_secret) # type: ignore + if tls.log_master_secret is not None + else None + ), + server_name=server_name, + cafile=settings.ca_file, + capath=settings.ca_path, + certificate=settings.certificate, + certificate_chain=settings.certificate_chain, + cipher_suites=settings.cipher_suites, + private_key=settings.certificate_private_key, + verify_mode=settings.verify_mode, + max_datagram_frame_size=65536, + ) diff --git a/mitmproxy/proxy/layers/tls.py b/mitmproxy/proxy/layers/tls.py index ab8ea154ce..bf253fbda9 100644 --- a/mitmproxy/proxy/layers/tls.py +++ b/mitmproxy/proxy/layers/tls.py @@ -1,5 +1,6 @@ import struct import time +import typing from collections.abc import Iterator from dataclasses import dataclass from logging import DEBUG @@ -11,6 +12,7 @@ from mitmproxy import certs from mitmproxy import connection +from mitmproxy.connection import TlsVersion from mitmproxy.net.tls import starts_like_dtls_record from mitmproxy.net.tls import starts_like_tls_record from mitmproxy.proxy import commands @@ -157,7 +159,9 @@ def dtls_parse_client_hello(data: bytes) -> ClientHello | None: HTTP1_ALPNS = (b"http/1.1", b"http/1.0", b"http/0.9") -HTTP_ALPNS = (b"h2",) + HTTP1_ALPNS +HTTP2_ALPN = b"h2" +HTTP3_ALPN = b"h3" +HTTP_ALPNS = (HTTP3_ALPN, HTTP2_ALPN, *HTTP1_ALPNS) # We need these classes as hooks can only have one argument at the moment. @@ -319,8 +323,10 @@ def receive_handshake_data( elif last_err in [ ("SSL routines", "ssl3_read_bytes", "tlsv1 alert unknown ca"), ("SSL routines", "ssl3_read_bytes", "sslv3 alert bad certificate"), + ("SSL routines", "ssl3_read_bytes", "ssl/tls alert bad certificate"), ("SSL routines", "", "tlsv1 alert unknown ca"), # OpenSSL 3+ ("SSL routines", "", "sslv3 alert bad certificate"), # OpenSSL 3+ + ("SSL routines", "", "ssl/tls alert bad certificate"), # OpenSSL 3.2+ ]: assert isinstance(last_err, tuple) err = last_err[2] @@ -329,6 +335,8 @@ def receive_handshake_data( in [ ("SSL routines", "ssl3_get_record", "wrong version number"), ("SSL routines", "", "wrong version number"), # OpenSSL 3+ + ("SSL routines", "", "packet length too long"), # OpenSSL 3+ + ("SSL routines", "", "record layer failure"), # OpenSSL 3+ ] and data[:4].isascii() ): @@ -356,14 +364,24 @@ def receive_handshake_data( cert = self.tls.get_peer_certificate() if cert: all_certs.insert(0, cert) + self.conn.certificate_list = [] + for cert in all_certs: + try: + # This may fail for weird certs, https://github.com/mitmproxy/mitmproxy/issues/6968. + parsed_cert = certs.Cert.from_pyopenssl(cert) + except ValueError as e: + yield commands.Log( + f"{self.debug}[tls] failed to parse certificate: {e}", WARNING + ) + else: + self.conn.certificate_list.append(parsed_cert) self.conn.timestamp_tls_setup = time.time() self.conn.alpn = self.tls.get_alpn_proto_negotiated() - self.conn.certificate_list = [ - certs.Cert.from_pyopenssl(x) for x in all_certs - ] self.conn.cipher = self.tls.get_cipher_name() - self.conn.tls_version = self.tls.get_protocol_version_name() + self.conn.tls_version = typing.cast( + TlsVersion, self.tls.get_protocol_version_name() + ) if self.debug: yield commands.Log( f"{self.debug}[tls] tls established: {self.conn}", DEBUG diff --git a/mitmproxy/proxy/layers/udp.py b/mitmproxy/proxy/layers/udp.py index fd7e65227f..e7a889c847 100644 --- a/mitmproxy/proxy/layers/udp.py +++ b/mitmproxy/proxy/layers/udp.py @@ -119,13 +119,11 @@ def relay_messages(self, event: events.Event) -> layer.CommandGenerator[None]: yield commands.SendData(send_to, event.data) elif isinstance(event, events.ConnectionClosed): - if send_to.connected: - yield commands.CloseConnection(send_to) - else: - self._handle_event = self.done - if self.flow: - yield UdpEndHook(self.flow) - self.flow.live = False + self._handle_event = self.done + yield commands.CloseConnection(send_to) + if self.flow: + yield UdpEndHook(self.flow) + self.flow.live = False else: raise AssertionError(f"Unexpected event: {event}") diff --git a/mitmproxy/proxy/mode_servers.py b/mitmproxy/proxy/mode_servers.py index 5ada94ed11..fb6ab66dfa 100644 --- a/mitmproxy/proxy/mode_servers.py +++ b/mitmproxy/proxy/mode_servers.py @@ -9,6 +9,7 @@ await inst.start() # TCP server is running now. """ + from __future__ import annotations import asyncio @@ -32,13 +33,11 @@ from typing import TypeVar import mitmproxy_rs - from mitmproxy import ctx from mitmproxy import flow from mitmproxy import platform from mitmproxy.connection import Address from mitmproxy.net import local_ip -from mitmproxy.net import udp from mitmproxy.proxy import commands from mitmproxy.proxy import layers from mitmproxy.proxy import mode_specs @@ -85,8 +84,7 @@ class ServerManager(typing.Protocol): @contextmanager def register_connection( self, connection_id: tuple | str, handler: ProxyConnectionHandler - ): - ... # pragma: no cover + ): ... # pragma: no cover class ServerInstance(Generic[M], metaclass=ABCMeta): @@ -183,75 +181,44 @@ def to_json(self) -> dict: "listen_addrs": self.listen_addrs, } - async def handle_tcp_connection( + async def handle_stream( self, - reader: asyncio.StreamReader | mitmproxy_rs.TcpStream, - writer: asyncio.StreamWriter | mitmproxy_rs.TcpStream, + reader: asyncio.StreamReader | mitmproxy_rs.Stream, + writer: asyncio.StreamWriter | mitmproxy_rs.Stream, ) -> None: handler = ProxyConnectionHandler( ctx.master, reader, writer, ctx.options, self.mode ) handler.layer = self.make_top_layer(handler.layer.context) if isinstance(self.mode, mode_specs.TransparentMode): + assert isinstance(writer, asyncio.StreamWriter) s = cast(socket.socket, writer.get_extra_info("socket")) try: assert platform.original_addr original_dst = platform.original_addr(s) except Exception as e: logger.error(f"Transparent mode failure: {e!r}") + writer.close() return else: handler.layer.context.client.sockname = original_dst handler.layer.context.server.address = original_dst - elif isinstance(self.mode, (mode_specs.WireGuardMode, mode_specs.LocalMode)): + elif isinstance( + self.mode, (mode_specs.WireGuardMode, mode_specs.LocalMode) + ): # pragma: no cover on platforms without wg-test-client handler.layer.context.server.address = writer.get_extra_info( - "destination_address", handler.layer.context.client.sockname + "remote_endpoint", handler.layer.context.client.sockname ) with self.manager.register_connection(handler.layer.context.client.id, handler): await handler.handle_client() - def handle_udp_datagram( - self, - transport: asyncio.DatagramTransport | mitmproxy_rs.DatagramTransport, - data: bytes, - remote_addr: Address, - local_addr: Address, - ) -> None: - # temporary workaround: we don't have a client uuid here. - connection_id = (remote_addr, local_addr) - if connection_id not in self.manager.connections: - reader = udp.DatagramReader() - writer = udp.DatagramWriter(transport, remote_addr, reader) - handler = ProxyConnectionHandler( - ctx.master, reader, writer, ctx.options, self.mode - ) - handler.timeout_watchdog.CONNECTION_TIMEOUT = 20 - handler.layer = self.make_top_layer(handler.layer.context) - handler.layer.context.client.transport_protocol = "udp" - handler.layer.context.server.transport_protocol = "udp" - if isinstance(self.mode, (mode_specs.WireGuardMode, mode_specs.LocalMode)): - handler.layer.context.server.address = local_addr - - # pre-register here - we may get datagrams before the task is executed. - self.manager.connections[connection_id] = handler - t = asyncio.create_task(self.handle_udp_connection(connection_id, handler)) - # assign it somewhere so that it does not get garbage-collected. - handler._handle_udp_task = t # type: ignore - else: - handler = self.manager.connections[connection_id] - reader = cast(udp.DatagramReader, handler.transports[handler.client].reader) - reader.feed_data(data, remote_addr) - - async def handle_udp_connection( - self, connection_id: tuple, handler: ProxyConnectionHandler - ) -> None: - with self.manager.register_connection(connection_id, handler): - await handler.handle_client() + async def handle_udp_stream(self, stream: mitmproxy_rs.Stream) -> None: + await self.handle_stream(stream, stream) class AsyncioServerInstance(ServerInstance[M], metaclass=ABCMeta): - _servers: list[asyncio.Server | udp.UdpServer] + _servers: list[asyncio.Server | mitmproxy_rs.udp.UdpServer] def __init__(self, *args, **kwargs) -> None: self._servers = [] @@ -263,14 +230,22 @@ def is_running(self) -> bool: @property def listen_addrs(self) -> tuple[Address, ...]: - return tuple( - sock.getsockname() for serv in self._servers for sock in serv.sockets - ) + addrs = [] + for s in self._servers: + if isinstance(s, mitmproxy_rs.udp.UdpServer): + addrs.append(s.getsockname()) + else: + try: + addrs.extend(sock.getsockname() for sock in s.sockets) + except OSError: # pragma: no cover + pass # this can fail during shutdown, see https://github.com/mitmproxy/mitmproxy/issues/6529 + return tuple(addrs) async def _start(self) -> None: assert not self._servers host = self.mode.listen_host(ctx.options.listen_host) port = self.mode.listen_port(ctx.options.listen_port) + assert port is not None try: self._servers = await self.listen(host, port) except OSError as e: @@ -295,8 +270,12 @@ async def _stop(self) -> None: async def listen( self, host: str, port: int - ) -> list[asyncio.Server | udp.UdpServer]: - if self.mode.transport_protocol == "tcp": + ) -> list[asyncio.Server | mitmproxy_rs.udp.UdpServer]: + if self.mode.transport_protocol not in ("tcp", "udp", "both"): + raise AssertionError(self.mode.transport_protocol) + + servers: list[asyncio.Server | mitmproxy_rs.udp.UdpServer] = [] + if self.mode.transport_protocol in ("tcp", "both"): # workaround for https://github.com/python/cpython/issues/89856: # We want both IPv4 and IPv6 sockets to bind to the same port. # This may fail (https://github.com/mitmproxy/mitmproxy/pull/5542#issuecomment-1222803291), @@ -305,55 +284,63 @@ async def listen( try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("", 0)) - fixed_port = s.getsockname()[1] + port = s.getsockname()[1] s.close() - return [ - await asyncio.start_server( - self.handle_tcp_connection, host, fixed_port - ) - ] + servers.append( + await asyncio.start_server(self.handle_stream, host, port) + ) except Exception as e: logger.debug( f"Failed to listen on a single port ({e!r}), falling back to default behavior." ) - return [await asyncio.start_server(self.handle_tcp_connection, host, port)] - elif self.mode.transport_protocol == "udp": - # create_datagram_endpoint only creates one (non-dual-stack) socket, so we spawn two servers instead. - if not host: - ipv4 = await udp.start_server( - self.handle_udp_datagram, + port = 0 + servers.append( + await asyncio.start_server(self.handle_stream, host, port) + ) + else: + servers.append( + await asyncio.start_server(self.handle_stream, host, port) + ) + if self.mode.transport_protocol in ("udp", "both"): + # we start two servers for dual-stack support. + # On Linux, this would also be achievable by toggling IPV6_V6ONLY off, but this here works cross-platform. + if host == "": + ipv4 = await mitmproxy_rs.udp.start_udp_server( "0.0.0.0", port, + self.handle_udp_stream, ) + servers.append(ipv4) try: - ipv6 = await udp.start_server( - self.handle_udp_datagram, - "::", - port or ipv4.sockets[0].getsockname()[1], + ipv6 = await mitmproxy_rs.udp.start_udp_server( + "[::]", + ipv4.getsockname()[1], + self.handle_udp_stream, ) + servers.append(ipv6) # pragma: no cover except Exception: # pragma: no cover logger.debug("Failed to listen on '::', listening on IPv4 only.") - return [ipv4] - else: # pragma: no cover - return [ipv4, ipv6] - return [ - await udp.start_server( - self.handle_udp_datagram, - host, - port, + else: + servers.append( + await mitmproxy_rs.udp.start_udp_server( + host, + port, + self.handle_udp_stream, + ) ) - ] - else: - raise AssertionError(self.mode.transport_protocol) + + return servers class WireGuardServerInstance(ServerInstance[mode_specs.WireGuardMode]): - _server: mitmproxy_rs.WireGuardServer | None = None + _server: mitmproxy_rs.wireguard.WireGuardServer | None = None server_key: str client_key: str - def make_top_layer(self, context: Context) -> Layer: + def make_top_layer( + self, context: Context + ) -> Layer: # pragma: no cover on platforms without wg-test-client return layers.modes.TransparentProxy(context) @property @@ -371,6 +358,7 @@ async def _start(self) -> None: assert self._server is None host = self.mode.listen_host(ctx.options.listen_host) port = self.mode.listen_port(ctx.options.listen_port) + assert port is not None if self.mode.data: conf_path = Path(self.mode.data).expanduser() @@ -382,8 +370,8 @@ async def _start(self) -> None: conf_path.write_text( json.dumps( { - "server_key": mitmproxy_rs.genkey(), - "client_key": mitmproxy_rs.genkey(), + "server_key": mitmproxy_rs.wireguard.genkey(), + "client_key": mitmproxy_rs.wireguard.genkey(), }, indent=4, ) @@ -396,16 +384,16 @@ async def _start(self) -> None: except Exception as e: raise ValueError(f"Invalid configuration file ({conf_path}): {e}") from e # error early on invalid keys - p = mitmproxy_rs.pubkey(self.client_key) - _ = mitmproxy_rs.pubkey(self.server_key) + p = mitmproxy_rs.wireguard.pubkey(self.client_key) + _ = mitmproxy_rs.wireguard.pubkey(self.server_key) - self._server = await mitmproxy_rs.start_wireguard_server( - host, + self._server = await mitmproxy_rs.wireguard.start_wireguard_server( + host or "0.0.0.0", port, self.server_key, [p], - self.wg_handle_tcp_connection, - self.handle_udp_datagram, + self.wg_handle_stream, + self.wg_handle_stream, ) conf = self.client_conf() @@ -415,7 +403,11 @@ async def _start(self) -> None: def client_conf(self) -> str | None: if not self._server: return None - host = local_ip.get_local_ip() or local_ip.get_local_ip6() + host = ( + self.mode.listen_host(ctx.options.listen_host) + or local_ip.get_local_ip() + or local_ip.get_local_ip6() + ) port = self.mode.listen_port(ctx.options.listen_port) return textwrap.dedent( f""" @@ -425,7 +417,7 @@ def client_conf(self) -> str | None: DNS = 10.0.0.53 [Peer] - PublicKey = {mitmproxy_rs.pubkey(self.server_key)} + PublicKey = {mitmproxy_rs.wireguard.pubkey(self.server_key)} AllowedIPs = 0.0.0.0/0 Endpoint = {host}:{port} """ @@ -442,12 +434,14 @@ async def _stop(self) -> None: finally: self._server = None - async def wg_handle_tcp_connection(self, stream: mitmproxy_rs.TcpStream) -> None: - await self.handle_tcp_connection(stream, stream) + async def wg_handle_stream( + self, stream: mitmproxy_rs.Stream + ) -> None: # pragma: no cover on platforms without wg-test-client + await self.handle_stream(stream, stream) class LocalRedirectorInstance(ServerInstance[mode_specs.LocalMode]): - _server: ClassVar[mitmproxy_rs.LocalRedirector | None] = None + _server: ClassVar[mitmproxy_rs.local.LocalRedirector | None] = None """The local redirector daemon. Will be started once and then reused for all future instances.""" _instance: ClassVar[LocalRedirectorInstance | None] = None """The current LocalRedirectorInstance. Will be unset again if an instance is stopped.""" @@ -461,36 +455,19 @@ def make_top_layer(self, context: Context) -> Layer: return layers.modes.TransparentProxy(context) @classmethod - async def redirector_handle_tcp_connection( - cls, stream: mitmproxy_rs.TcpStream - ) -> None: - if cls._instance is not None: - await cls._instance.handle_tcp_connection(stream, stream) - - @classmethod - def redirector_handle_datagram( + async def redirector_handle_stream( cls, - transport: mitmproxy_rs.DatagramTransport, - data: bytes, - remote_addr: Address, - local_addr: Address, + stream: mitmproxy_rs.Stream, ) -> None: if cls._instance is not None: - cls._instance.handle_udp_datagram( - transport=transport, - data=data, - remote_addr=remote_addr, - local_addr=local_addr, - ) + await cls._instance.handle_stream(stream, stream) async def _start(self) -> None: if self._instance: raise RuntimeError("Cannot spawn more than one local redirector.") - if self.mode.data.startswith("!"): - spec = f"{self.mode.data},{os.getpid()}" - elif self.mode.data: - spec = self.mode.data + if self.mode.data: + spec = f"{self.mode.data},!{os.getpid()}" else: spec = f"!{os.getpid()}" @@ -498,9 +475,9 @@ async def _start(self) -> None: cls._instance = self # assign before awaiting to avoid races if cls._server is None: try: - cls._server = await mitmproxy_rs.start_local_redirector( - cls.redirector_handle_tcp_connection, - cls.redirector_handle_datagram, + cls._server = await mitmproxy_rs.local.start_local_redirector( + cls.redirector_handle_stream, + cls.redirector_handle_stream, ) except Exception: cls._instance = None diff --git a/mitmproxy/proxy/mode_specs.py b/mitmproxy/proxy/mode_specs.py index f9a7542142..cc65aa847c 100644 --- a/mitmproxy/proxy/mode_specs.py +++ b/mitmproxy/proxy/mode_specs.py @@ -19,6 +19,7 @@ RegularMode.parse("socks5") # ValueError """ + from __future__ import annotations import dataclasses @@ -31,7 +32,6 @@ from typing import Literal import mitmproxy_rs - from mitmproxy.coretypes.serializable import Serializable from mitmproxy.net import server_spec @@ -81,7 +81,7 @@ def description(self) -> str: """The mode description that will be used in server logs and UI.""" @property - def default_port(self) -> int: + def default_port(self) -> int | None: """ Default listen port of servers for this mode, see `ProxyMode.listen_port()`. """ @@ -89,7 +89,7 @@ def default_port(self) -> int: @property @abstractmethod - def transport_protocol(self) -> Literal["tcp", "udp"] | None: + def transport_protocol(self) -> Literal["tcp", "udp", "both"]: """The transport protocol used by this mode's server.""" @classmethod @@ -146,11 +146,12 @@ def listen_host(self, default: str | None = None) -> str: else: return "" - def listen_port(self, default: int | None = None) -> int: + def listen_port(self, default: int | None = None) -> int | None: """ Return the port a server for this mode should listen on. This can be either directly specified in the spec, taken from a user-configured global default (`options.listen_port`), or from `ProxyMode.default_port`. + May be `None` for modes that don't bind to a specific address, e.g. local redirect mode. """ if self.custom_listen_port is not None: return self.custom_listen_port @@ -171,8 +172,9 @@ def set_state(self, state): raise dataclasses.FrozenInstanceError("Proxy modes are immutable.") -TCP: Literal["tcp", "udp"] = "tcp" -UDP: Literal["tcp", "udp"] = "udp" +TCP: Literal["tcp", "udp", "both"] = "tcp" +UDP: Literal["tcp", "udp", "both"] = "udp" +BOTH: Literal["tcp", "udp", "both"] = "both" def _check_empty(data): @@ -229,12 +231,14 @@ class ReverseMode(ProxyMode): # noinspection PyDataclass def __post_init__(self) -> None: self.scheme, self.address = server_spec.parse(self.data, default_scheme="https") - if self.scheme in ("http3", "dtls", "udp", "dns", "quic"): + if self.scheme in ("http3", "dtls", "udp", "quic"): self.transport_protocol = UDP + elif self.scheme in ("dns", "https"): + self.transport_protocol = BOTH self.description = f"{self.description} to {self.data}" @property - def default_port(self) -> int: + def default_port(self) -> int | None: if self.scheme == "dns": return 53 return super().default_port @@ -256,7 +260,7 @@ class DnsMode(ProxyMode): description = "DNS server" default_port = 53 - transport_protocol = UDP + transport_protocol = BOTH def __post_init__(self) -> None: _check_empty(self.data) @@ -290,18 +294,20 @@ class LocalMode(ProxyMode): """OS-level transparent proxy.""" description = "Local redirector" - transport_protocol = None + transport_protocol = BOTH + default_port = None def __post_init__(self) -> None: # should not raise - mitmproxy_rs.LocalRedirector.describe_spec(self.data) + mitmproxy_rs.local.LocalRedirector.describe_spec(self.data) class OsProxyMode(ProxyMode): # pragma: no cover """Deprecated alias for LocalMode""" description = "Deprecated alias for LocalMode" - transport_protocol = None + transport_protocol = BOTH + default_port = None def __post_init__(self) -> None: raise ValueError( diff --git a/mitmproxy/proxy/server.py b/mitmproxy/proxy/server.py index c990261924..1071138d76 100644 --- a/mitmproxy/proxy/server.py +++ b/mitmproxy/proxy/server.py @@ -6,6 +6,7 @@ - Process any commands from layer (such as opening a server connection) - Wait for any IO and send it as events to top layer. """ + import abc import asyncio import collections @@ -19,9 +20,9 @@ from types import TracebackType from typing import Literal -import mitmproxy_rs from OpenSSL import SSL +import mitmproxy_rs from mitmproxy import http from mitmproxy import options as moptions from mitmproxy import tls @@ -29,7 +30,6 @@ from mitmproxy.connection import Client from mitmproxy.connection import Connection from mitmproxy.connection import ConnectionState -from mitmproxy.net import udp from mitmproxy.proxy import commands from mitmproxy.proxy import events from mitmproxy.proxy import layer @@ -44,14 +44,18 @@ logger = logging.getLogger(__name__) +TCP_TIMEOUT = 60 * 10 +UDP_TIMEOUT = 20 + class TimeoutWatchdog: last_activity: float - CONNECTION_TIMEOUT = 10 * 60 + timeout: int can_timeout: asyncio.Event blocker: int - def __init__(self, callback: Callable[[], Awaitable]): + def __init__(self, timeout: int, callback: Callable[[], Awaitable]): + self.timeout = timeout self.callback = callback self.last_activity = time.time() self.can_timeout = asyncio.Event() @@ -65,10 +69,8 @@ async def watch(self): try: while True: await self.can_timeout.wait() - await asyncio.sleep( - self.CONNECTION_TIMEOUT - (time.time() - self.last_activity) - ) - if self.last_activity + self.CONNECTION_TIMEOUT < time.time(): + await asyncio.sleep(self.timeout - (time.time() - self.last_activity)) + if self.last_activity + self.timeout < time.time(): await self.callback() return except asyncio.CancelledError: @@ -90,12 +92,8 @@ def disarm(self): @dataclass class ConnectionIO: handler: asyncio.Task | None = None - reader: None | ( - asyncio.StreamReader | udp.DatagramReader | mitmproxy_rs.TcpStream - ) = None - writer: None | ( - asyncio.StreamWriter | udp.DatagramWriter | mitmproxy_rs.TcpStream - ) = None + reader: asyncio.StreamReader | mitmproxy_rs.Stream | None = None + writer: asyncio.StreamWriter | mitmproxy_rs.Stream | None = None class ConnectionHandler(metaclass=abc.ABCMeta): @@ -118,7 +116,13 @@ def __init__(self, context: Context) -> None: # In a reverse proxy scenario, this is necessary as we would otherwise hang # on protocols that start with a server greeting. self.layer = layer.NextLayer(context, ask_on_start=True) - self.timeout_watchdog = TimeoutWatchdog(self.on_timeout) + if self.client.transport_protocol == "tcp": + timeout = TCP_TIMEOUT + else: + timeout = UDP_TIMEOUT + self.timeout_watchdog = TimeoutWatchdog(timeout, self.on_timeout) + + self._server_event_lock = asyncio.Lock() # workaround for https://bugs.python.org/issue40124 / https://bugs.python.org/issue29930 self._drain_lock = asyncio.Lock() @@ -142,13 +146,13 @@ async def handle_client(self) -> None: assert writer writer.close() else: + await self.server_event(events.Start()) handler = asyncio_utils.create_task( self.handle_connection(self.client), name=f"client connection handler", client=self.client.peername, ) self.transports[self.client].handler = handler - self.server_event(events.Start()) await asyncio.wait([handler]) if not handler.cancelled() and (e := handler.exception()): self.log( @@ -179,7 +183,7 @@ async def handle_client(self) -> None: async def open_connection(self, command: commands.OpenConnection) -> None: if not command.connection.address: self.log(f"Cannot open connection, no hostname given.") - self.server_event( + await self.server_event( events.OpenConnectionCompleted( command, f"Cannot open connection, no hostname given." ) @@ -194,14 +198,15 @@ async def open_connection(self, command: commands.OpenConnection) -> None: self.log( f"server connection to {human.format_address(command.connection.address)} killed before connect: {err}" ) - self.server_event( + await self.handle_hook(server_hooks.ServerConnectErrorHook(hook_data)) + await self.server_event( events.OpenConnectionCompleted(command, f"Connection killed: {err}") ) return async with self.max_conns[command.connection.address]: - reader: asyncio.StreamReader | udp.DatagramReader - writer: asyncio.StreamWriter | udp.DatagramWriter + reader: asyncio.StreamReader | mitmproxy_rs.Stream + writer: asyncio.StreamWriter | mitmproxy_rs.Stream try: command.connection.timestamp_start = time.time() if command.connection.transport_protocol == "tcp": @@ -210,7 +215,7 @@ async def open_connection(self, command: commands.OpenConnection) -> None: local_addr=command.connection.sockname, ) elif command.connection.transport_protocol == "udp": - reader, writer = await udp.open_connection( + reader = writer = await mitmproxy_rs.udp.open_udp_connection( *command.connection.address, local_addr=command.connection.sockname, ) @@ -222,7 +227,8 @@ async def open_connection(self, command: commands.OpenConnection) -> None: err = "connection cancelled" self.log(f"error establishing server connection: {err}") command.connection.error = err - self.server_event(events.OpenConnectionCompleted(command, err)) + await self.handle_hook(server_hooks.ServerConnectErrorHook(hook_data)) + await self.server_event(events.OpenConnectionCompleted(command, err)) if isinstance(e, asyncio.CancelledError): # From https://docs.python.org/3/library/asyncio-exceptions.html#asyncio.CancelledError: # > In almost all situations the exception must be re-raised. @@ -235,8 +241,11 @@ async def open_connection(self, command: commands.OpenConnection) -> None: command.connection.state = ConnectionState.OPEN command.connection.peername = writer.get_extra_info("peername") command.connection.sockname = writer.get_extra_info("sockname") - self.transports[command.connection].reader = reader - self.transports[command.connection].writer = writer + self.transports[command.connection] = ConnectionIO( + handler=asyncio.current_task(), + reader=reader, + writer=writer, + ) assert command.connection.peername if command.connection.address[0] != command.connection.peername[0]: @@ -245,29 +254,23 @@ async def open_connection(self, command: commands.OpenConnection) -> None: addr = human.format_address(command.connection.address) self.log(f"server connect {addr}") await self.handle_hook(server_hooks.ServerConnectedHook(hook_data)) - self.server_event(events.OpenConnectionCompleted(command, None)) - - # during connection opening, this function is the designated handler that can be cancelled. - # once we have a connection, we do want the teardown here to happen in any case, so we - # reassign the handler to .handle_connection and then clean up here once that is done. - new_handler = asyncio_utils.create_task( - self.handle_connection(command.connection), - name=f"server connection handler for {addr}", - client=self.client.peername, - ) - self.transports[command.connection].handler = new_handler - await asyncio.wait([new_handler]) - - self.log(f"server disconnect {addr}") - command.connection.timestamp_end = time.time() - await self.handle_hook(server_hooks.ServerDisconnectedHook(hook_data)) + await self.server_event(events.OpenConnectionCompleted(command, None)) + + try: + await self.handle_connection(command.connection) + finally: + self.log(f"server disconnect {addr}") + command.connection.timestamp_end = time.time() + await self.handle_hook( + server_hooks.ServerDisconnectedHook(hook_data) + ) async def wakeup(self, request: commands.RequestWakeup) -> None: await asyncio.sleep(request.delay) task = asyncio.current_task() assert task is not None self.wakeup_timer.discard(task) - self.server_event(events.Wakeup(request)) + await self.server_event(events.Wakeup(request)) async def handle_connection(self, connection: Connection) -> None: """ @@ -289,7 +292,7 @@ async def handle_connection(self, connection: Connection) -> None: cancelled = e break - self.server_event(events.DataReceived(connection, data)) + await self.server_event(events.DataReceived(connection, data)) try: await self.drain_writers() @@ -297,18 +300,22 @@ async def handle_connection(self, connection: Connection) -> None: cancelled = e break - if cancelled is None: + if cancelled is None and connection.transport_protocol == "tcp": + # TCP connections can be half-closed. connection.state &= ~ConnectionState.CAN_READ else: connection.state = ConnectionState.CLOSED - self.server_event(events.ConnectionClosed(connection)) + await self.server_event(events.ConnectionClosed(connection)) - if cancelled is None and connection.state is ConnectionState.CAN_WRITE: + if connection.state is ConnectionState.CAN_WRITE: # we may still use this connection to *send* stuff, # even though the remote has closed their side of the connection. # to make this work we keep this task running and wait for cancellation. - await asyncio.Event().wait() + try: + await asyncio.Event().wait() + except asyncio.CancelledError as e: + cancelled = e try: writer = self.transports[connection].writer @@ -336,15 +343,21 @@ async def drain_writers(self): transport.handler.cancel(f"Error sending data: {e}") async def on_timeout(self) -> None: - self.log(f"Closing connection due to inactivity: {self.client}") - handler = self.transports[self.client].handler - assert handler - handler.cancel("timeout") + try: + handler = self.transports[self.client].handler + except KeyError: # pragma: no cover + # there is a super short window between connection close and watchdog cancellation + pass + else: + if self.client.transport_protocol == "tcp": + self.log(f"Closing connection due to inactivity: {self.client}") + assert handler + handler.cancel("timeout") async def hook_task(self, hook: commands.StartHook) -> None: await self.handle_hook(hook) if hook.blocking: - self.server_event(events.HookCompleted(hook)) + await self.server_event(events.HookCompleted(hook)) @abc.abstractmethod async def handle_hook(self, hook: commands.StartHook) -> None: @@ -362,56 +375,67 @@ def log( level, message, extra={"client": self.client.peername}, exc_info=exc_info ) - def server_event(self, event: events.Event) -> None: - self.timeout_watchdog.register_activity() - try: - layer_commands = self.layer.handle_event(event) - for command in layer_commands: - if isinstance(command, commands.OpenConnection): - assert command.connection not in self.transports - handler = asyncio_utils.create_task( - self.open_connection(command), - name=f"server connection manager {command.connection.address}", - client=self.client.peername, - ) - self.transports[command.connection] = ConnectionIO(handler=handler) - elif isinstance(command, commands.RequestWakeup): - task = asyncio_utils.create_task( - self.wakeup(command), - name=f"wakeup timer ({command.delay:.1f}s)", - client=self.client.peername, - ) - assert task is not None - self.wakeup_timer.add(task) - elif ( - isinstance(command, commands.ConnectionCommand) - and command.connection not in self.transports - ): - pass # The connection has already been closed. - elif isinstance(command, commands.SendData): - writer = self.transports[command.connection].writer - assert writer - if not writer.is_closing(): - writer.write(command.data) - elif isinstance(command, commands.CloseTcpConnection): - self.close_connection(command.connection, command.half_close) - elif isinstance(command, commands.CloseConnection): - self.close_connection(command.connection, False) - elif isinstance(command, commands.StartHook): - t = asyncio_utils.create_task( - self.hook_task(command), - name=f"handle_hook({command.name})", - client=self.client.peername, - ) - # Python 3.11 Use TaskGroup instead. - self.hook_tasks.add(t) - t.add_done_callback(self.hook_tasks.remove) - elif isinstance(command, commands.Log): - self.log(command.message, command.level) - else: - raise RuntimeError(f"Unexpected command: {command}") - except Exception: - self.log(f"mitmproxy has crashed!", logging.ERROR, exc_info=True) + async def server_event(self, event: events.Event) -> None: + # server_event is supposed to be completely sync without any `await` that could pause execution. + # However, create_task with an [eager task factory] will schedule tasks immediately, + # which causes [reentrancy issues]. So we put the entire thing behind a lock. + # + # [eager task factory]: https://docs.python.org/3/library/asyncio-task.html#eager-task-factory + # [reentrancy issues]: https://github.com/mitmproxy/mitmproxy/issues/7027. + async with self._server_event_lock: + # No `await` beyond this point. + + self.timeout_watchdog.register_activity() + try: + layer_commands = self.layer.handle_event(event) + for command in layer_commands: + if isinstance(command, commands.OpenConnection): + assert command.connection not in self.transports + handler = asyncio_utils.create_task( + self.open_connection(command), + name=f"server connection handler {command.connection.address}", + client=self.client.peername, + ) + self.transports[command.connection] = ConnectionIO( + handler=handler + ) + elif isinstance(command, commands.RequestWakeup): + task = asyncio_utils.create_task( + self.wakeup(command), + name=f"wakeup timer ({command.delay:.1f}s)", + client=self.client.peername, + ) + assert task is not None + self.wakeup_timer.add(task) + elif ( + isinstance(command, commands.ConnectionCommand) + and command.connection not in self.transports + ): + pass # The connection has already been closed. + elif isinstance(command, commands.SendData): + writer = self.transports[command.connection].writer + assert writer + if not writer.is_closing(): + writer.write(command.data) + elif isinstance(command, commands.CloseTcpConnection): + self.close_connection(command.connection, command.half_close) + elif isinstance(command, commands.CloseConnection): + self.close_connection(command.connection, False) + elif isinstance(command, commands.StartHook): + t = asyncio_utils.create_task( + self.hook_task(command), + name=f"handle_hook({command.name})", + client=self.client.peername, + ) + # Python 3.11 Use TaskGroup instead. + self.hook_tasks.add(t) + t.add_done_callback(self.hook_tasks.remove) + elif isinstance(command, commands.Log): + self.log(command.message, command.level) + else: + raise RuntimeError(f"Unexpected command: {command}") + except Exception: + self.log(f"mitmproxy has crashed!", logging.ERROR, exc_info=True) def close_connection( self, connection: Connection, half_close: bool = False @@ -442,23 +466,15 @@ def close_connection( class LiveConnectionHandler(ConnectionHandler, metaclass=abc.ABCMeta): def __init__( self, - reader: asyncio.StreamReader | mitmproxy_rs.TcpStream, - writer: asyncio.StreamWriter | mitmproxy_rs.TcpStream, + reader: asyncio.StreamReader | mitmproxy_rs.Stream, + writer: asyncio.StreamWriter | mitmproxy_rs.Stream, options: moptions.Options, mode: mode_specs.ProxyMode, ) -> None: - # mitigate impact of https://github.com/mitmproxy/mitmproxy/issues/6204: - # For UDP, we don't get an accurate sockname from the transport when binding to all interfaces, - # however we would later need that to generate matching certificates. - # Until this is fixed properly, we can at least make the localhost case work. - sockname = writer.get_extra_info("sockname") - if sockname == "::": - sockname = "::1" - elif sockname == "0.0.0.0": - sockname = "127.0.0.1" client = Client( + transport_protocol=writer.get_extra_info("transport_protocol", "tcp"), peername=writer.get_extra_info("peername"), - sockname=sockname, + sockname=writer.get_extra_info("sockname"), timestamp_start=time.time(), proxy_mode=mode, state=ConnectionState.OPEN, @@ -475,9 +491,9 @@ class SimpleConnectionHandler(LiveConnectionHandler): # pragma: no cover hook_handlers: dict[str, Callable] - def __init__(self, reader, writer, options, mode, hooks): + def __init__(self, reader, writer, options, mode, hook_handlers): super().__init__(reader, writer, options, mode) - self.hook_handlers = hooks + self.hook_handlers = hook_handlers async def handle_hook(self, hook: commands.StartHook) -> None: if hook.name in self.hook_handlers: diff --git a/mitmproxy/proxy/server_hooks.py b/mitmproxy/proxy/server_hooks.py index a00c6ca195..1da4b60f22 100644 --- a/mitmproxy/proxy/server_hooks.py +++ b/mitmproxy/proxy/server_hooks.py @@ -63,3 +63,14 @@ class ServerDisconnectedHook(commands.StartHook): """ data: ServerConnectionHookData + + +@dataclass +class ServerConnectErrorHook(commands.StartHook): + """ + Mitmproxy failed to connect to a server. + + Every server connection will receive either a server_connected or a server_connect_error event, but not both. + """ + + data: ServerConnectionHookData diff --git a/mitmproxy/proxy/utils.py b/mitmproxy/proxy/utils.py index d2b2aa23aa..114a8e1555 100644 --- a/mitmproxy/proxy/utils.py +++ b/mitmproxy/proxy/utils.py @@ -1,6 +1,7 @@ """ Utility decorators that help build state machines """ + import functools from mitmproxy.proxy import events @@ -33,3 +34,35 @@ def _check_event_type(self, event: events.Event): return f return decorator + + +class ReceiveBuffer: + """ + A data structure to collect stream contents efficiently in O(n). + """ + + _chunks: list[bytes] + _len: int + + def __init__(self): + self._chunks = [] + self._len = 0 + + def __iadd__(self, other: bytes): + assert isinstance(other, bytes) + self._chunks.append(other) + self._len += len(other) + return self + + def __len__(self): + return self._len + + def __bytes__(self): + return b"".join(self._chunks) + + def __bool__(self): + return self._len > 0 + + def clear(self): + self._chunks.clear() + self._len = 0 diff --git a/mitmproxy/script/concurrent.py b/mitmproxy/script/concurrent.py index 587a65e78e..757548b643 100644 --- a/mitmproxy/script/concurrent.py +++ b/mitmproxy/script/concurrent.py @@ -2,6 +2,7 @@ This module provides a @concurrent decorator primitive to offload computations from mitmproxy's main master thread. """ + import asyncio import inspect diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py index efd3868340..a1e901753b 100644 --- a/mitmproxy/tools/cmdline.py +++ b/mitmproxy/tools/cmdline.py @@ -49,6 +49,7 @@ def common_options(parser, opts): opts.make_parser(parser, "mode", short="m") opts.make_parser(parser, "anticache") opts.make_parser(parser, "showhost") + opts.make_parser(parser, "show_ignored_hosts") opts.make_parser(parser, "rfile", metavar="PATH", short="r") opts.make_parser(parser, "scripts", metavar="SCRIPT", short="s") opts.make_parser(parser, "stickycookie", metavar="FILTER") diff --git a/mitmproxy/tools/console/commandexecutor.py b/mitmproxy/tools/console/commandexecutor.py index fea007fe9a..f047f54bca 100644 --- a/mitmproxy/tools/console/commandexecutor.py +++ b/mitmproxy/tools/console/commandexecutor.py @@ -19,11 +19,11 @@ def __call__(self, cmd: str) -> None: logging.error(str(e)) else: if ret is not None: - if type(ret) == Sequence[flow.Flow]: + if type(ret) == Sequence[flow.Flow]: # noqa: E721 signals.status_message.send( message="Command returned %s flows" % len(ret) ) - elif type(ret) == flow.Flow: + elif type(ret) is flow.Flow: signals.status_message.send(message="Command returned 1 flow") else: self.master.overlay( diff --git a/mitmproxy/tools/console/commands.py b/mitmproxy/tools/console/commands.py index ee10492549..67c1f18993 100644 --- a/mitmproxy/tools/console/commands.py +++ b/mitmproxy/tools/console/commands.py @@ -15,8 +15,7 @@ class CommandItem(urwid.WidgetWrap): def __init__(self, walker, cmd: command.Command, focused: bool): self.walker, self.cmd, self.focused = walker, cmd, focused - super().__init__(None) - self._w = self.get_widget() + super().__init__(self.get_widget()) def get_widget(self): parts = [("focus", ">> " if self.focused else " "), ("title", self.cmd.name)] @@ -112,14 +111,14 @@ def __init__(self, master): def set_active(self, val): h = urwid.Text("Command Help") style = "heading" if val else "heading_inactive" - self.header = urwid.AttrWrap(h, style) + self.header = urwid.AttrMap(h, style) def widget(self, txt): cols, _ = self.master.ui.get_cols_rows() return urwid.ListBox([urwid.Text(i) for i in textwrap.wrap(txt, cols)]) def sig_mod(self, txt): - self.set_body(self.widget(txt)) + self.body = self.widget(txt) class Commands(urwid.Pile, layoutwidget.LayoutWidget): diff --git a/mitmproxy/tools/console/common.py b/mitmproxy/tools/console/common.py index bd5b8f89f5..28f4714a50 100644 --- a/mitmproxy/tools/console/common.py +++ b/mitmproxy/tools/console/common.py @@ -95,8 +95,8 @@ def fcol(s: str, attr: str) -> tuple[str, int, urwid.Text]: SYMBOL_REPLAY = "\u21ba" SYMBOL_RETURN = "\u2190" SYMBOL_MARK = "\u25cf" - SYMBOL_UP = "\u21E7" - SYMBOL_DOWN = "\u21E9" + SYMBOL_UP = "\u21e7" + SYMBOL_DOWN = "\u21e9" SYMBOL_ELLIPSIS = "\u2026" SYMBOL_FROM_CLIENT = "\u21d2" SYMBOL_TO_CLIENT = "\u21d0" @@ -188,7 +188,7 @@ def render(self, size, focus=False): text = text[::-1] attr = attr[::-1] - text_len = urwid.util.calc_width(text, 0, len(text)) + text_len = urwid.calc_width(text, 0, len(text)) if size is not None and len(size) > 0: width = size[0] else: @@ -762,7 +762,7 @@ def format_flow( duration = f.messages[-1].timestamp - f.client_conn.timestamp_start else: duration = None - if f.client_conn.tls_version == "QUIC": + if f.client_conn.tls_version == "QUICv1": protocol = "quic" else: protocol = f.type diff --git a/mitmproxy/tools/console/consoleaddons.py b/mitmproxy/tools/console/consoleaddons.py index 6810bc42a5..66763a2206 100644 --- a/mitmproxy/tools/console/consoleaddons.py +++ b/mitmproxy/tools/console/consoleaddons.py @@ -375,7 +375,9 @@ def edit_focus_options(self) -> Sequence[str]: flow = self.master.view.focus.flow focus_options = [] - if isinstance(flow, tcp.TCPFlow): + if flow is None: + raise exceptions.CommandError("No flow selected.") + elif isinstance(flow, tcp.TCPFlow): focus_options = ["tcp-message"] elif isinstance(flow, udp.UDPFlow): focus_options = ["udp-message"] @@ -396,6 +398,8 @@ def edit_focus_options(self) -> Sequence[str]: "set-cookies", "url", ] + if flow.websocket: + focus_options.append("websocket-message") elif isinstance(flow, dns.DNSFlow): raise exceptions.CommandError( "Cannot edit DNS flows yet, please submit a patch." @@ -467,6 +471,10 @@ def edit_focus(self, flow_part: str) -> None: message = flow.messages[-1] c = self.master.spawn_editor(message.content or b"") message.content = c.rstrip(b"\n") + elif flow_part == "websocket-message": + message = flow.websocket.messages[-1] + c = self.master.spawn_editor(message.content or b"") + message.content = c.rstrip(b"\n") def _grideditor(self): gewidget = self.master.window.current("grideditor") diff --git a/mitmproxy/tools/console/defaultkeys.py b/mitmproxy/tools/console/defaultkeys.py index 41ac65bc56..2294538c35 100644 --- a/mitmproxy/tools/console/defaultkeys.py +++ b/mitmproxy/tools/console/defaultkeys.py @@ -74,7 +74,7 @@ def map(km: Keymap) -> None: "D", "view.flows.duplicate @focus", ["flowlist", "flowview"], "Duplicate flow" ) km.add( - "e", + "x", """ console.choose.cmd Format export.formats console.command export.file {choice} @focus @@ -156,7 +156,7 @@ def map(km: Keymap) -> None: console.choose.cmd Part console.edit.focus.options console.edit.focus {choice} """, - ["flowview"], + ["flowlist", "flowview"], "Edit a flow component", ) km.add( diff --git a/mitmproxy/tools/console/flowdetailview.py b/mitmproxy/tools/console/flowdetailview.py index b8b2745549..e3a28b91a6 100644 --- a/mitmproxy/tools/console/flowdetailview.py +++ b/mitmproxy/tools/console/flowdetailview.py @@ -80,7 +80,7 @@ def flowdetails(state, flow: mitmproxy.flow.Flow): ] if c.altnames: - parts.append(("Alt names", ", ".join(c.altnames))) + parts.append(("Alt names", ", ".join(str(x.value) for x in c.altnames))) text.extend(common.format_keyvals(parts, indent=4)) if cc is not None: diff --git a/mitmproxy/tools/console/flowview.py b/mitmproxy/tools/console/flowview.py index 191edd8c88..a57ead7402 100644 --- a/mitmproxy/tools/console/flowview.py +++ b/mitmproxy/tools/console/flowview.py @@ -117,7 +117,14 @@ def tab_http_request(self): def tab_http_response(self): flow = self.flow assert isinstance(flow, http.HTTPFlow) - if self.flow.intercepted and flow.response: + + # there is no good way to detect what part of the flow is intercepted, + # so we apply some heuristics to see if it's the HTTP response. + websocket_started = flow.websocket and len(flow.websocket.messages) != 0 + response_is_intercepted = ( + self.flow.intercepted and flow.response and not websocket_started + ) + if response_is_intercepted: return "Response intercepted" else: return "Response" @@ -145,7 +152,14 @@ def tab_udp_stream(self): return "UDP Stream" def tab_websocket_messages(self): - return "WebSocket Messages" + flow = self.flow + assert isinstance(flow, http.HTTPFlow) + assert flow.websocket + + if self.flow.intercepted and len(flow.websocket.messages) != 0: + return "WebSocket Messages intercepted" + else: + return "WebSocket Messages" def tab_details(self): return "Detail" @@ -187,7 +201,7 @@ def _contentview_status_bar(self, description: str, viewmode: str): align="right", ), ] - contentview_status_bar = urwid.AttrWrap(urwid.Columns(cols), "heading") + contentview_status_bar = urwid.AttrMap(urwid.Columns(cols), "heading") return contentview_status_bar FROM_CLIENT_MARKER = ("from_client", f"{common.SYMBOL_FROM_CLIENT} ") @@ -398,7 +412,7 @@ def conn_text(self, conn): align="right", ), ] - title = urwid.AttrWrap(urwid.Columns(cols), "heading") + title = urwid.AttrMap(urwid.Columns(cols), "heading") txt.append(title) txt.extend(body) diff --git a/mitmproxy/tools/console/grideditor/base.py b/mitmproxy/tools/console/grideditor/base.py index 8510e91996..f03be63279 100644 --- a/mitmproxy/tools/console/grideditor/base.py +++ b/mitmproxy/tools/console/grideditor/base.py @@ -21,13 +21,11 @@ @overload -def read_file(filename: str, escaped: Literal[True]) -> bytes: - ... +def read_file(filename: str, escaped: Literal[True]) -> bytes: ... @overload -def read_file(filename: str, escaped: Literal[False]) -> str: - ... +def read_file(filename: str, escaped: Literal[False]) -> str: ... def read_file(filename: str, escaped: bool) -> bytes | str: @@ -101,11 +99,11 @@ def __init__( w = self.editor.columns[i].Display(v) if focused == i: if i in errors: - w = urwid.AttrWrap(w, "focusfield_error") + w = urwid.AttrMap(w, "focusfield_error") else: - w = urwid.AttrWrap(w, "focusfield") + w = urwid.AttrMap(w, "focusfield") elif i in errors: - w = urwid.AttrWrap(w, "field_error") + w = urwid.AttrMap(w, "field_error") self.fields.append(w) fspecs = self.fields[:] @@ -113,7 +111,7 @@ def __init__( fspecs[0] = ("fixed", self.editor.first_width + 2, fspecs[0]) w = urwid.Columns(fspecs, dividechars=2) if focused is not None: - w.set_focus_column(focused) + w.focus_position = focused super().__init__(w) def keypress(self, s, k): @@ -297,7 +295,7 @@ def __init__( else: headings.append(c) h = urwid.Columns(headings, dividechars=2) - h = urwid.AttrWrap(h, "heading") + h = urwid.AttrMap(h, "heading") self.walker = GridWalker(self.value, self) self.lb = GridListBox(self.walker) @@ -315,16 +313,14 @@ def layout_popping(self): def show_empty_msg(self): if self.walker.lst: - self._w.set_footer(None) + self._w.footer = None else: - self._w.set_footer( - urwid.Text( - [ - ("highlight", "No values - you should add some. Press "), - ("key", "?"), - ("highlight", " for help."), - ] - ) + self._w.footer = urwid.Text( + [ + ("highlight", "No values - you should add some. Press "), + ("key", "?"), + ("highlight", " for help."), + ] ) def set_subeditor_value(self, val, focus, focus_col): diff --git a/mitmproxy/tools/console/grideditor/col_bytes.py b/mitmproxy/tools/console/grideditor/col_bytes.py index 9af1a3544d..0ac4a7ed1c 100644 --- a/mitmproxy/tools/console/grideditor/col_bytes.py +++ b/mitmproxy/tools/console/grideditor/col_bytes.py @@ -37,11 +37,11 @@ class Edit(base.Cell): def __init__(self, data: bytes) -> None: d = strutils.bytes_to_escaped_str(data) w = urwid.Edit(edit_text=d, wrap="any", multiline=True) - w = urwid.AttrWrap(w, "editfield") + w = urwid.AttrMap(w, "editfield") super().__init__(w) def get_data(self) -> bytes: - txt = self._w.get_text()[0].strip() + txt = self._w.base_widget.get_text()[0].strip() try: return strutils.escaped_str_to_bytes(txt) except ValueError: diff --git a/mitmproxy/tools/console/grideditor/col_text.py b/mitmproxy/tools/console/grideditor/col_text.py index 04dbb5ab04..d5ad1cba03 100644 --- a/mitmproxy/tools/console/grideditor/col_text.py +++ b/mitmproxy/tools/console/grideditor/col_text.py @@ -4,6 +4,7 @@ In a nutshell, text columns are actually a proxy class for byte columns, which just encode/decodes contents. """ + from mitmproxy.tools.console import signals from mitmproxy.tools.console.grideditor import col_bytes diff --git a/mitmproxy/tools/console/grideditor/col_viewany.py b/mitmproxy/tools/console/grideditor/col_viewany.py index b6ffe1f442..50ffe2a7d3 100644 --- a/mitmproxy/tools/console/grideditor/col_viewany.py +++ b/mitmproxy/tools/console/grideditor/col_viewany.py @@ -1,6 +1,7 @@ """ A display-only column that displays any data type. """ + from typing import Any import urwid diff --git a/mitmproxy/tools/console/keybindings.py b/mitmproxy/tools/console/keybindings.py index 4a200833f1..a9d7237657 100644 --- a/mitmproxy/tools/console/keybindings.py +++ b/mitmproxy/tools/console/keybindings.py @@ -12,8 +12,7 @@ class KeyItem(urwid.WidgetWrap): def __init__(self, walker, binding, focused): self.walker, self.binding, self.focused = walker, binding, focused - super().__init__(None) - self._w = self.get_widget() + super().__init__(self.get_widget()) def get_widget(self): cmd = textwrap.dedent(self.binding.command).strip() @@ -116,14 +115,14 @@ def __init__(self, master, keybinding_focus_change): def set_active(self, val): h = urwid.Text("Key Binding Help") style = "heading" if val else "heading_inactive" - self.header = urwid.AttrWrap(h, style) + self.header = urwid.AttrMap(h, style) def widget(self, txt): cols, _ = self.master.ui.get_cols_rows() return urwid.ListBox([urwid.Text(i) for i in textwrap.wrap(txt, cols)]) def sig_mod(self, txt): - self.set_body(self.widget(txt)) + self.body = self.widget(txt) class KeyBindings(urwid.Pile, layoutwidget.LayoutWidget): @@ -146,13 +145,13 @@ def __init__(self, master): def get_focused_binding(self): if self.focus_position != 0: return None - f = self.widget_list[0] + f = self.contents[0][0] return f.walker.get_focus()[0].binding def keypress(self, size, key): if key == "m_next": self.focus_position = (self.focus_position + 1) % len(self.widget_list) - self.widget_list[1].set_active(self.focus_position == 1) + self.contents[1][0].set_active(self.focus_position == 1) key = None # This is essentially a copypasta from urwid.Pile's keypress handler. @@ -160,6 +159,5 @@ def keypress(self, size, key): item_rows = None if len(size) == 2: item_rows = self.get_item_rows(size, focus=True) - i = self.widget_list.index(self.focus_item) - tsize = self.get_item_size(size, i, True, item_rows) - return self.focus_item.keypress(tsize, key) + tsize = self.get_item_size(size, self.focus_position, True, item_rows) + return self.focus.keypress(tsize, key) diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py index ee303ff5d2..a0a1d73d1b 100644 --- a/mitmproxy/tools/console/master.py +++ b/mitmproxy/tools/console/master.py @@ -29,6 +29,7 @@ from mitmproxy.tools.console import palettes from mitmproxy.tools.console import signals from mitmproxy.tools.console import window +from mitmproxy.utils import strutils T = TypeVar("T", str, bytes) @@ -120,12 +121,23 @@ def get_editor(self) -> str: else: return "vi" + def get_hex_editor(self) -> str: + editors = ["ghex", "bless", "hexedit", "hxd", "hexer", "hexcurse"] + for editor in editors: + if shutil.which(editor): + return editor + return self.get_editor() + def spawn_editor(self, data: T) -> T: - text = not isinstance(data, bytes) + text = isinstance(data, str) fd, name = tempfile.mkstemp("", "mitmproxy", text=text) + with_hexeditor = isinstance(data, bytes) and strutils.is_mostly_bin(data) with open(fd, "w" if text else "wb") as f: f.write(data) - c = self.get_editor() + if with_hexeditor: + c = self.get_hex_editor() + else: + c = self.get_editor() cmd = shlex.split(c) cmd.append(name) with self.uistopped(): diff --git a/mitmproxy/tools/console/options.py b/mitmproxy/tools/console/options.py index 8aca078bac..1e52cca258 100644 --- a/mitmproxy/tools/console/options.py +++ b/mitmproxy/tools/console/options.py @@ -2,6 +2,7 @@ import pprint import textwrap +import typing from collections.abc import Sequence from typing import Optional @@ -33,12 +34,11 @@ def __init__(self, walker, opt, focused, namewidth, editing): self.walker, self.opt, self.focused = walker, opt, focused self.namewidth = namewidth self.editing = editing - super().__init__(None) - self._w = self.get_widget() + super().__init__(self.get_widget()) def get_widget(self): val = self.opt.current() - if self.opt.typespec == bool: + if self.opt.typespec is bool: displayval = "true" if val else "false" elif not val: displayval = "" @@ -190,7 +190,7 @@ def keypress(self, size, key): self.walker._modified() elif key == "m_select": foc, idx = self.get_focus() - if foc.opt.typespec == bool: + if foc.opt.typespec is bool: self.master.options.toggler(foc.opt.name)() # Bust the focus widget cache self.set_focus(self.walker.index) @@ -207,7 +207,7 @@ def keypress(self, size, key): self.master.options.setter(foc.opt.name), ) ) - elif foc.opt.typespec == Sequence[str]: + elif foc.opt.typespec in (Sequence[str], typing.Sequence[str]): self.master.overlay( overlay.OptionsOverlay( self.master, @@ -231,14 +231,14 @@ def __init__(self, master): def set_active(self, val): h = urwid.Text("Option Help") style = "heading" if val else "heading_inactive" - self.header = urwid.AttrWrap(h, style) + self.header = urwid.AttrMap(h, style) def widget(self, txt): cols, _ = self.master.ui.get_cols_rows() return urwid.ListBox([urwid.Text(i) for i in textwrap.wrap(txt, cols)]) def update_help_text(self, txt: str) -> None: - self.set_body(self.widget(txt)) + self.body = self.widget(txt) class Options(urwid.Pile, layoutwidget.LayoutWidget): @@ -273,6 +273,5 @@ def keypress(self, size, key): item_rows = None if len(size) == 2: item_rows = self.get_item_rows(size, focus=True) - i = self.widget_list.index(self.focus_item) - tsize = self.get_item_size(size, i, True, item_rows) - return self.focus_item.keypress(tsize, key) + tsize = self.get_item_size(size, self.focus_position, True, item_rows) + return self.focus.keypress(tsize, key) diff --git a/mitmproxy/tools/console/overlay.py b/mitmproxy/tools/console/overlay.py index 17b55bc10a..fad1dd4449 100644 --- a/mitmproxy/tools/console/overlay.py +++ b/mitmproxy/tools/console/overlay.py @@ -45,7 +45,7 @@ def __init__(self, txt, focus, current, shortcut): else: s = "option_selected" if focus else "text" super().__init__( - urwid.AttrWrap( + urwid.AttrMap( urwid.Padding(urwid.Text(txt)), s, ) @@ -107,7 +107,7 @@ def __init__(self, master, title, choices, current, callback): self.walker = ChooserListWalker(choices, current) super().__init__( - urwid.AttrWrap( + urwid.AttrMap( urwid.LineBox( urwid.BoxAdapter(urwid.ListBox(self.walker), len(choices)), title=title, @@ -152,7 +152,7 @@ def __init__(self, master, name, vals, vspace): cols, rows = master.ui.get_cols_rows() self.ge = grideditor.OptionsEditor(master, name, vals) super().__init__( - urwid.AttrWrap( + urwid.AttrMap( urwid.LineBox(urwid.BoxAdapter(self.ge, rows - vspace), title=name), "background", ) @@ -176,7 +176,7 @@ def __init__(self, master, vals): cols, rows = master.ui.get_cols_rows() self.ge = grideditor.DataViewer(master, vals) super().__init__( - urwid.AttrWrap( + urwid.AttrMap( urwid.LineBox(urwid.BoxAdapter(self.ge, rows - 5), title="Data viewer"), "background", ) diff --git a/mitmproxy/tools/console/palettes.py b/mitmproxy/tools/console/palettes.py index a6b5d2e73c..087b4a3061 100644 --- a/mitmproxy/tools/console/palettes.py +++ b/mitmproxy/tools/console/palettes.py @@ -146,7 +146,6 @@ def gen_rgb_gradient(palette, cols): class LowDark(Palette): - """ Low-color dark background """ @@ -247,7 +246,6 @@ class Dark(LowDark): class LowLight(Palette): - """ Low-color light background """ diff --git a/mitmproxy/tools/console/quickhelp.py b/mitmproxy/tools/console/quickhelp.py index d6c959ad9a..663a03cfad 100644 --- a/mitmproxy/tools/console/quickhelp.py +++ b/mitmproxy/tools/console/quickhelp.py @@ -1,6 +1,7 @@ """ This module is reponsible for drawing the quick key help at the bottom of mitmproxy. """ + from dataclasses import dataclass from typing import Union @@ -73,6 +74,7 @@ def make( top_items["Unmark"] = "Toggle mark on this flow" else: top_items["Mark"] = "Toggle mark on this flow" + top_items["Edit"] = "Edit a flow component" if focused_flow.intercepted: top_items["Resume"] = "Resume this intercepted flow" if focused_flow.modified(): diff --git a/mitmproxy/tools/console/signals.py b/mitmproxy/tools/console/signals.py index 38c3f5cfac..63d5f59a00 100644 --- a/mitmproxy/tools/console/signals.py +++ b/mitmproxy/tools/console/signals.py @@ -10,8 +10,7 @@ # Show a status message in the action bar # Instead of using this signal directly, consider emitting a log event. -def _status_message(message: StatusMessage, expire: int = 5) -> None: - ... +def _status_message(message: StatusMessage, expire: int = 5) -> None: ... status_message = signals.SyncSignal(_status_message) @@ -20,8 +19,7 @@ def _status_message(message: StatusMessage, expire: int = 5) -> None: # Prompt for input def _status_prompt( prompt: str, text: str | None, callback: Callable[[str], None] -) -> None: - ... +) -> None: ... status_prompt = signals.SyncSignal(_status_prompt) @@ -30,24 +28,21 @@ def _status_prompt( # Prompt for a single keystroke def _status_prompt_onekey( prompt: str, keys: list[tuple[str, str]], callback: Callable[[str], None] -) -> None: - ... +) -> None: ... status_prompt_onekey = signals.SyncSignal(_status_prompt_onekey) # Prompt for a command -def _status_prompt_command(partial: str = "", cursor: int | None = None) -> None: - ... +def _status_prompt_command(partial: str = "", cursor: int | None = None) -> None: ... status_prompt_command = signals.SyncSignal(_status_prompt_command) # Call a callback in N seconds -def _call_in(seconds: float, callback: Callable[[], None]) -> None: - ... +def _call_in(seconds: float, callback: Callable[[], None]) -> None: ... call_in = signals.SyncSignal(_call_in) diff --git a/mitmproxy/tools/console/statusbar.py b/mitmproxy/tools/console/statusbar.py index 71b5d41d96..705427647b 100644 --- a/mitmproxy/tools/console/statusbar.py +++ b/mitmproxy/tools/console/statusbar.py @@ -332,7 +332,7 @@ def redraw(self) -> None: else: boundaddr = "" t.extend(self.get_status()) - status = urwid.AttrWrap( + status = urwid.AttrMap( urwid.Columns( [ urwid.Text(t), diff --git a/mitmproxy/tools/console/tabs.py b/mitmproxy/tools/console/tabs.py index a3ba09a109..adf9c481f9 100644 --- a/mitmproxy/tools/console/tabs.py +++ b/mitmproxy/tools/console/tabs.py @@ -8,7 +8,7 @@ def __init__(self, offset, content, attr, onclick): """ p = urwid.Text(content, align="center") p = urwid.Padding(p, align="center", width=("relative", 100)) - p = urwid.AttrWrap(p, attr) + p = urwid.AttrMap(p, attr) urwid.WidgetWrap.__init__(self, p) self.offset = offset self.onclick = onclick @@ -21,11 +21,10 @@ def mouse_event(self, size, event, button, col, row, focus): class Tabs(urwid.WidgetWrap): def __init__(self, tabs, tab_offset=0): - super().__init__("") + super().__init__(urwid.Pile([])) self.tab_offset = tab_offset self.tabs = tabs self.show() - self._w = urwid.Pile([]) def change_tab(self, offset): self.tab_offset = offset @@ -56,4 +55,4 @@ def show(self): self._w = urwid.Frame( body=self.tabs[self.tab_offset % len(self.tabs)][1](), header=headers ) - self._w.set_focus("body") + self._w.focus_position = "body" diff --git a/mitmproxy/tools/console/window.py b/mitmproxy/tools/console/window.py index 6c2e24926b..8c3a6de1fc 100644 --- a/mitmproxy/tools/console/window.py +++ b/mitmproxy/tools/console/window.py @@ -23,7 +23,7 @@ def __init__(self, window, widget, title, focus): self.window = window if title: - header = urwid.AttrWrap( + header = urwid.AttrMap( urwid.Text(title), "heading" if focus else "heading_inactive" ) else: @@ -129,7 +129,7 @@ class Window(urwid.Frame): def __init__(self, master): self.statusbar = statusbar.StatusBar(master) super().__init__( - None, header=None, footer=urwid.AttrWrap(self.statusbar, "background") + None, header=None, footer=urwid.AttrMap(self.statusbar, "background") ) self.master = master self.master.view.sig_view_refresh.connect(self.view_changed) @@ -185,7 +185,7 @@ def wrapped(idx): focus_column=self.pane, ) - self.body = urwid.AttrWrap(w, "background") + self.body = urwid.AttrMap(w, "background") signals.window_refresh.send() def flow_changed(self, flow: flow.Flow) -> None: diff --git a/mitmproxy/tools/main.py b/mitmproxy/tools/main.py index cc3c9ddeeb..ae662ee85d 100644 --- a/mitmproxy/tools/main.py +++ b/mitmproxy/tools/main.py @@ -116,10 +116,20 @@ def _sigint(*_): def _sigterm(*_): loop.call_soon_threadsafe(master.shutdown) - # We can't use loop.add_signal_handler because that's not available on Windows' Proactorloop, - # but signal.signal just works fine for our purposes. - signal.signal(signal.SIGINT, _sigint) - signal.signal(signal.SIGTERM, _sigterm) + try: + # Prefer loop.add_signal_handler where it is available + # https://github.com/mitmproxy/mitmproxy/issues/7128 + loop.add_signal_handler(signal.SIGINT, _sigint) + loop.add_signal_handler(signal.SIGTERM, _sigterm) + except NotImplementedError: + # Fall back to `signal.signal` for platforms where that is not available (Windows' Proactorloop) + signal.signal(signal.SIGINT, _sigint) + signal.signal(signal.SIGTERM, _sigterm) + + # to fix the issue mentioned https://github.com/mitmproxy/mitmproxy/issues/6744 + # by setting SIGPIPE to SIG_IGN, the process will not terminate and continue to run + if hasattr(signal, "SIGPIPE"): + signal.signal(signal.SIGPIPE, signal.SIG_IGN) await master.run() return master diff --git a/mitmproxy/tools/web/app.py b/mitmproxy/tools/web/app.py index f031d6787f..5352f8a799 100644 --- a/mitmproxy/tools/web/app.py +++ b/mitmproxy/tools/web/app.py @@ -6,6 +6,7 @@ import logging import os.path import re +import sys from collections.abc import Callable from collections.abc import Sequence from io import BytesIO @@ -18,6 +19,7 @@ import mitmproxy.flow import mitmproxy.tools.web.master +import mitmproxy_rs from mitmproxy import certs from mitmproxy import command from mitmproxy import contentviews @@ -37,6 +39,12 @@ from mitmproxy.utils.strutils import always_str from mitmproxy.websocket import WebSocketMessage +TRANSPARENT_PNG = ( + b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08" + b"\x04\x00\x00\x00\xb5\x1c\x0c\x02\x00\x00\x00\x0bIDATx\xdac\xfc\xff\x07" + b"\x00\x02\x00\x01\xfc\xa8Q\rh\x00\x00\x00\x00IEND\xaeB`\x82" +) + def cert_to_json(certs: Sequence[certs.Cert]) -> dict | None: if not certs: @@ -50,7 +58,7 @@ def cert_to_json(certs: Sequence[certs.Cert]) -> dict | None: "serial": str(cert.serial), "subject": cert.subject, "issuer": cert.issuer, - "altnames": cert.altnames, + "altnames": [str(x.value) for x in cert.altnames], } @@ -284,7 +292,7 @@ class WebSocketEventBroadcaster(tornado.websocket.WebSocketHandler): connections: ClassVar[set[WebSocketEventBroadcaster]] _send_tasks: ClassVar[set[asyncio.Task]] = set() - def open(self): + def open(self, *args, **kwargs): self.connections.add(self) def on_close(self): @@ -308,7 +316,7 @@ def broadcast(cls, **kwargs): "utf8", "surrogateescape" ) - for conn in cls.connections: + for conn in cls.connections.copy(): cls.send(conn, message) @@ -448,6 +456,8 @@ def put(self, flow_id) -> None: raise APIError(400, f"Unknown update response.{k}: {v}") elif a == "marked": flow.marked = b + elif a == "comment": + flow.comment = b else: raise APIError(400, f"Unknown update {a}: {b}") except APIError: @@ -635,16 +645,56 @@ def get(self): class State(RequestHandler): + # Separate method for testability. + @staticmethod + def get_json(master: mitmproxy.tools.web.master.WebMaster): + return { + "version": version.VERSION, + "contentViews": [v.name for v in contentviews.views if v.name != "Query"], + "servers": { + s.mode.full_spec: s.to_json() for s in master.proxyserver.servers + }, + "platform": sys.platform, + } + def get(self): - self.write( + self.write(State.get_json(self.master)) + + +class ProcessList(RequestHandler): + @staticmethod + def get_json(): + processes = mitmproxy_rs.process_info.active_executables() + return [ { - "version": version.VERSION, - "contentViews": [ - v.name for v in contentviews.views if v.name != "Query" - ], - "servers": [s.to_json() for s in self.master.proxyserver.servers], + "is_visible": process.is_visible, + "executable": process.executable, + "is_system": process.is_system, + "display_name": process.display_name, } - ) + for process in processes + ] + + def get(self): + self.write(ProcessList.get_json()) + + +class ProcessImage(RequestHandler): + def get(self): + path = self.get_query_argument("path", None) + + if not path: + raise APIError(400, "Missing 'path' parameter.") + + try: + icon_bytes = mitmproxy_rs.process_info.executable_icon(path) + except Exception: + icon_bytes = TRANSPARENT_PNG + + self.set_header("Content-Type", "image/png") + self.set_header("X-Content-Type-Options", "nosniff") + self.set_header("Cache-Control", "max-age=604800") + self.write(icon_bytes) class GZipContentAndFlowFiles(tornado.web.GZipContentEncoding): @@ -706,5 +756,7 @@ def __init__( (r"/options(?:\.json)?", Options), (r"/options/save", SaveOptions), (r"/state(?:\.json)?", State), + (r"/processes", ProcessList), + (r"/executable-icon", ProcessImage), ], ) diff --git a/mitmproxy/tools/web/master.py b/mitmproxy/tools/web/master.py index e80ca45688..5ec3ac6025 100644 --- a/mitmproxy/tools/web/master.py +++ b/mitmproxy/tools/web/master.py @@ -42,7 +42,7 @@ def __init__(self, opts: options.Options, with_termlog: bool = True): self.addons.add( webaddons.WebAddon(), intercept.Intercept(), - readfile.ReadFile(), + readfile.ReadFileStdin(), static_viewer.StaticViewer(), self.view, self.events, @@ -86,7 +86,11 @@ def _sig_servers_changed(self) -> None: app.ClientConnection.broadcast( resource="state", cmd="update", - data={"servers": [s.to_json() for s in self.proxyserver.servers]}, + payload={ + "servers": { + s.mode.full_spec: s.to_json() for s in self.proxyserver.servers + } + }, ) async def running(self): diff --git a/mitmproxy/tools/web/static/app.css b/mitmproxy/tools/web/static/app.css index 1c9b4eac2e..9691ceda6f 100644 --- a/mitmproxy/tools/web/static/app.css +++ b/mitmproxy/tools/web/static/app.css @@ -1,2 +1,2 @@ -html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}.resource-icon{width:32px;height:32px}.resource-icon-css{background-image:url(images/chrome-devtools/resourceCSSIcon.png)}.resource-icon-document{background-image:url(images/chrome-devtools/resourceDocumentIcon.png)}.resource-icon-js{background-image:url(images/chrome-devtools/resourceJSIcon.png)}.resource-icon-plain{background-image:url(images/chrome-devtools/resourcePlainIcon.png)}.resource-icon-executable{background-image:url(images/resourceExecutableIcon.png)}.resource-icon-flash{background-image:url(images/resourceFlashIcon.png)}.resource-icon-image{background-image:url(images/resourceImageIcon.png)}.resource-icon-java{background-image:url(images/resourceJavaIcon.png)}.resource-icon-not-modified{background-image:url(images/resourceNotModifiedIcon.png)}.resource-icon-redirect{background-image:url(images/resourceRedirectIcon.png)}.resource-icon-websocket{background-image:url(images/resourceWebSocketIcon.png)}.resource-icon-tcp{background-image:url(images/resourceTcpIcon.png)}.resource-icon-udp{background-image:url(images/resourceUdpIcon.png)}.resource-icon-dns{background-image:url(images/resourceDnsIcon.png)}.resource-icon-quic{background-image:url(images/resourceQuicIcon.png)}#container,#mitmproxy,body,html{height:100%;margin:0;overflow:hidden}#container{display:flex;flex-direction:column;outline:0}#container>.eventlog,#container>footer,#container>header{flex:0 0 auto}.main-view{flex:1 1 auto;height:0;display:flex;flex-direction:row}.main-view.vertical{flex-direction:column}.main-view .flow-detail,.main-view .flow-table{flex:1 1 auto}.splitter{flex:0 0 1px;background-color:#aaa;position:relative}.splitter>div{position:absolute}.splitter.splitter-x{cursor:col-resize}.splitter.splitter-x>div{margin-left:-1px;width:4px;height:100%}.splitter.splitter-y{cursor:row-resize}.splitter.splitter-y>div{margin-top:-1px;height:4px;width:100%}.nav-tabs{border-bottom:solid #a6a6a6 1px}.nav-tabs>a{display:inline-block;border:solid transparent 1px;text-decoration:none}.nav-tabs>a.active{background-color:#fff;border-color:#a6a6a6;border-bottom-color:#fff}.nav-tabs>a.special{color:#fff;background-color:#396cad;border-bottom-color:#396cad}.nav-tabs>a.special:hover{background-color:#5386c6}.nav-tabs-lg>a{padding:3px 14px;margin:0 2px -1px}.nav-tabs-sm>a{padding:0 7px;margin:2px 2px -1px}header{padding-top:6px;background-color:#fff}header>div{display:block;margin:0;padding:0;border-bottom:solid #a6a6a6 1px;height:95px;overflow:visible}.menu-group{margin:0 5px 0 6px;display:inline-block;height:95px}.menu-content{height:79px;display:flow-root}.menu-content>a{display:inline-block}.menu-content>.btn,.menu-content>a>.btn{height:79px;text-align:center;margin:0 1px;padding:12px 5px;border:none;border-radius:0}.menu-content>.btn i,.menu-content>a>.btn i{font-size:20px;display:block;margin:0 auto 5px}.menu-content>.btn.btn-sm{height:26.33333333px;padding:0 5px}.menu-content>.btn.btn-sm i{display:inline-block;font-size:14px;margin:0}.menu-entry{text-align:left;height:26.33333333px;line-height:1;padding:.5rem 1rem}.menu-entry label{font-size:1.2rem;font-weight:400;margin:0}.menu-entry input[type=checkbox]{margin:0 2px;vertical-align:middle}.menu-legend{color:#777;height:16px;text-align:center;font-size:12px;padding:0 5px}.menu-group+.menu-group:before{margin-left:-6px;content:" ";border-left:solid 1px #e6e6e6;margin-top:10px;height:75px;position:absolute}.main-menu{display:flex}.main-menu .menu-group{width:50%}.main-menu .btn-sm{margin-top:6px}.filter-input{margin:4px 0}.filter-input .popover{top:27px;left:43px;display:block;max-width:none;opacity:.9}@media (max-width:767px){.filter-input .popover{top:16px;left:29px;right:2px}}.filter-input .popover .popover-content{max-height:500px;overflow-y:auto}.filter-input .popover .popover-content tr{cursor:pointer}.filter-input .popover .popover-content tr:hover{background-color:hsla(209,52%,84%,.5)!important}.connection-indicator{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;float:right;margin:5px;opacity:1;transition:all 1s linear}a.connection-indicator:focus,a.connection-indicator:hover{color:#fff;text-decoration:none;cursor:pointer}.connection-indicator:empty{display:none}.btn .connection-indicator{position:relative;top:-1px}.connection-indicator.fetching,.connection-indicator.init{background-color:#5bc0de}.connection-indicator.established{background-color:#5cb85c;opacity:0}.connection-indicator.error{background-color:#d9534f;transition:all .2s linear}.connection-indicator.offline{background-color:#f0ad4e;opacity:1}.flow-table{width:100%;overflow-y:scroll;overflow-x:hidden}.flow-table table{width:100%;table-layout:fixed}.flow-table thead tr{background-color:#f2f2f2;border-bottom:solid #bebebe 1px;line-height:23px}.flow-table th{font-weight:400;position:relative!important;padding-left:1px;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flow-table th.sort-asc,.flow-table th.sort-desc{background-color:#fafafa}.flow-table th.sort-asc:after,.flow-table th.sort-desc:after{font:normal normal normal 14px/1 FontAwesome;position:absolute;right:3px;top:3px;padding:2px;background-color:rgba(250,250,250,.8)}.flow-table th.sort-asc:after{content:"\f0de"}.flow-table th.sort-desc:after{content:"\f0dd"}.flow-table tr{cursor:pointer;background-color:#fff}.flow-table tr:nth-child(even){background-color:#f2f2f2}.flow-table tr.selected{background-color:#e0ebf5!important}.flow-table tr.selected.highlighted{background-color:#7bbefc!important}.flow-table tr.highlighted{background-color:#ffeb99}.flow-table tr.highlighted:nth-child(even){background-color:#ffe57f}.flow-table td{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.flow-table tr.intercepted:not(.has-response) .col-method,.flow-table tr.intercepted:not(.has-response) .col-path{color:#ff7f00}.flow-table tr.intercepted.has-response .col-size,.flow-table tr.intercepted.has-response .col-status,.flow-table tr.intercepted.has-response .col-time{color:#ff7f00}.flow-table .fa{line-height:inherit}.flow-table .col-tls{width:10px}.flow-table .col-tls-https{background-color:rgba(0,185,0,.5)}.flow-table .col-icon{width:32px}.flow-table .col-path .fa{margin-left:0;font-size:16px}.flow-table .col-path .fa-repeat{color:green}.flow-table .col-path .fa-pause{color:#ff7f00}.flow-table .col-path .fa-exclamation,.flow-table .col-path .fa-times{color:#8b0000}.flow-table .col-method{width:60px}.flow-table .col-version{width:80px}.flow-table .col-status{width:50px}.flow-table .col-size{width:70px}.flow-table .col-time{width:50px}.flow-table .col-timestamp{width:170px}.flow-table td.col-size,.flow-table td.col-time,.flow-table td.col-timestamp{text-align:right}.flow-table .col-quickactions{width:0;direction:rtl;overflow:hidden;background-color:inherit;font-size:20px}.flow-table .col-quickactions *{direction:ltr}.flow-table .col-quickactions.hover,.flow-table tr:hover .col-quickactions{overflow:visible}.flow-table .col-quickactions>div{height:32px;background-color:inherit;display:inline-flex;align-items:center}.flow-table .col-quickactions>div>a{margin-right:2px;height:32px;width:32px;border-radius:16px;text-align:center}.flow-table .col-quickactions>div>a:hover{background-color:rgba(0,0,0,.05)}.flow-table .col-quickactions .fa-play{transform:translate(1px,2px)}.flow-table .col-quickactions .fa-repeat{transform:translate(0,2px)}.flow-detail{width:100%;overflow:hidden;display:flex;flex-direction:column}.flow-detail nav{background-color:#f2f2f2}.flow-detail section{overflow-y:scroll;flex:1;padding:5px 12px 10px}.flow-detail section>footer{box-shadow:0 0 3px gray;padding:2px;margin:0;height:23px}.flow-detail .first-line{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;background-color:#428bca;color:#fff;margin:0 -8px 2px;padding:4px 8px;border-radius:5px;word-break:break-all;max-height:100px;overflow-y:auto}.flow-detail .contentview{margin:0 -12px;padding:0 12px}.flow-detail .contentview .controls{display:flex;align-items:center}.flow-detail .contentview .controls h5{flex:1;font-size:12px;font-weight:700;margin:10px 0}.flow-detail .contentview pre button:not(:only-child){margin-top:6px}.flow-detail hr{margin:0}.inline-input{display:inline;margin:0 -3px;padding:0 3px;border:solid transparent 1px}.inline-input:hover{box-shadow:0 0 0 1px rgba(0,0,0,.0125),0 2px 4px rgba(0,0,0,.05),0 2px 6px rgba(0,0,0,.025);background-color:rgba(255,255,255,.1)}.inline-input[placeholder]:empty:not(:focus-visible):before{content:attr(placeholder);color:#d3d3d3;font-style:italic}.inline-input[contenteditable]{outline-width:0;box-shadow:0 0 0 1px rgba(0,0,0,.05),0 2px 4px rgba(0,0,0,.2),0 2px 6px rgba(0,0,0,.1);background-color:rgba(255,255,255,.2)}.inline-input[contenteditable].has-warning{color:#ffb8b8}.certificate-table,.connection-table,.timing-table{width:100%;table-layout:fixed;word-break:break-all}.certificate-table td:nth-child(2),.connection-table td:nth-child(2),.timing-table td:nth-child(2){font-family:Menlo,Monaco,Consolas,"Courier New",monospace;width:70%}.certificate-table tr:not(:first-child),.connection-table tr:not(:first-child),.timing-table tr:not(:first-child){border-top:1px solid #f7f7f7}.certificate-table td,.connection-table td,.timing-table td{vertical-align:top}.connection-table td:first-child{padding-right:1em}.headers,.trailers{position:relative;min-height:2ex;overflow-wrap:break-word}.headers .kv-row,.trailers .kv-row{margin-bottom:.3em;max-height:12.4ex;overflow-y:auto}.headers .kv-key,.trailers .kv-key{font-weight:700}.headers .kv-value,.trailers .kv-value{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}.headers .inline-input,.trailers .inline-input{background-color:#fff}.headers .kv-add-row,.trailers .kv-add-row{opacity:0;color:#666;position:absolute;bottom:4px;right:4px;transition:all .1s ease-in-out}.headers:hover .kv-add-row,.trailers:hover .kv-add-row{opacity:1}.connection-table td,.timing-table td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}dl.cert-attributes{display:flex;flex-flow:row;flex-wrap:wrap;margin-bottom:0}dl.cert-attributes dd,dl.cert-attributes dt{text-overflow:ellipsis;overflow:hidden}dl.cert-attributes dt{flex:0 0 2em}dl.cert-attributes dd{flex:0 0 calc(100% - 2em)}.dns-request table td,.dns-request table th,.dns-response table td,.dns-response table th{padding-right:1rem}.flowview-image{text-align:center;padding:10px 0}.flowview-image img{max-width:100%;max-height:100%}.edit-flow-container{position:fixed;right:20px}.edit-flow{cursor:pointer;position:absolute;right:0;top:5px;height:40px;width:40px;border-radius:20px;z-index:10000;background-color:rgba(255,255,255,.7);border:solid 2px rgba(248,145,59,.7);text-align:center;font-size:22px;line-height:37px;transition:all .1s ease-in-out}.edit-flow:hover{background-color:rgba(239,108,0,.7);color:rgba(0,0,0,.8);border:solid 2px transparent}.eventlog{height:200px;flex:0 0 auto;display:flex;flex-direction:column}.eventlog>div{background-color:#f2f2f2;padding:0 5px;flex:0 0 auto;border-top:1px solid #aaa;cursor:row-resize}.eventlog>pre{flex:1 1 auto;margin:0;border-radius:0;overflow-x:auto;overflow-y:scroll;background-color:#fcfcfc}.eventlog .fa-close{cursor:pointer;float:right;color:grey;padding:3px 0;padding-left:10px}.eventlog .fa-close:hover{color:#000}.eventlog .btn-toggle{margin-top:-2px;margin-left:3px;padding:2px 2px;font-size:10px;line-height:10px;border-radius:2px}.eventlog .label{cursor:pointer;vertical-align:middle;display:inline-block;margin-top:-2px;margin-left:3px}footer{box-shadow:0 -1px 3px #d3d3d3;padding:0 0 4px 3px}footer .label{margin-right:3px}.CodeMirror{border:1px solid #ccc;height:auto!important}.CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:rgba(20,255,20,.5);-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite}.cm-animate-fat-cursor{width:auto;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none;outline:0}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.contentview .header{font-weight:700}.contentview .highlight{font-weight:700}.contentview .offset{color:#00f}.contentview .codeeditor{margin-bottom:12px}.contentview .Token_Name_Tag{color:#006400}.contentview .Token_Literal_String{color:#b22222}.contentview .Token_Literal_Number{color:purple}.contentview .Token_Keyword_Constant{color:#00f}.modal-visible{display:block}.modal-dialog{overflow-y:initial!important}.modal-body{max-height:calc(100vh - 200px);overflow-y:auto}.dropdown-menu{margin:0!important}.dropdown-menu>li>a{padding:3px 10px}.command-title{background-color:#f2f2f2;border:1px solid #aaa}.command-result{display:block;margin:0;background-color:#fcfcfc;height:100px;max-height:100px;overflow:auto}.command-suggestion{background-color:#9c9c9c}.argument-suggestion{background-color:hsla(209,52%,84%,.5)!important}.command>.popover{display:block;position:relative;max-width:none}.available-commands{overflow:auto}.wireguard-config{margin:1rem 0;display:flex;flex-wrap:wrap;column-gap:2rem;align-items:center}.wireguard-config>*{margin:0} +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}.resource-icon{width:32px;height:32px}.resource-icon-css{background-image:url(images/chrome-devtools/resourceCSSIcon.png)}.resource-icon-document{background-image:url(images/chrome-devtools/resourceDocumentIcon.png)}.resource-icon-js{background-image:url(images/chrome-devtools/resourceJSIcon.png)}.resource-icon-plain{background-image:url(images/chrome-devtools/resourcePlainIcon.png)}.resource-icon-executable{background-image:url(images/resourceExecutableIcon.png)}.resource-icon-flash{background-image:url(images/resourceFlashIcon.png)}.resource-icon-image{background-image:url(images/resourceImageIcon.png)}.resource-icon-java{background-image:url(images/resourceJavaIcon.png)}.resource-icon-not-modified{background-image:url(images/resourceNotModifiedIcon.png)}.resource-icon-redirect{background-image:url(images/resourceRedirectIcon.png)}.resource-icon-websocket{background-image:url(images/resourceWebSocketIcon.png)}.resource-icon-tcp{background-image:url(images/resourceTcpIcon.png)}.resource-icon-udp{background-image:url(images/resourceUdpIcon.png)}.resource-icon-dns{background-image:url(images/resourceDnsIcon.png)}.resource-icon-quic{background-image:url(images/resourceQuicIcon.png)}#container,#mitmproxy,body,html{height:100%;margin:0;overflow:hidden}#container{display:flex;flex-direction:column;outline:0}#container>.eventlog,#container>footer,#container>header{flex:0 0 auto}.main-view{flex:1 1 auto;height:0;display:flex;flex-direction:row}.main-view.vertical{flex-direction:column}.main-view .flow-detail,.main-view .flow-table{flex:1 1 auto}.splitter{flex:0 0 1px;background-color:#aaa;position:relative}.splitter>div{position:absolute}.splitter.splitter-x{cursor:col-resize}.splitter.splitter-x>div{margin-left:-1px;width:4px;height:100%}.splitter.splitter-y{cursor:row-resize}.splitter.splitter-y>div{margin-top:-1px;height:4px;width:100%}.nav-tabs{border-bottom:solid #a6a6a6 1px}.nav-tabs>a{display:inline-block;border:solid transparent 1px;text-decoration:none}.nav-tabs>a.active{background-color:#fff;border-color:#a6a6a6;border-bottom-color:#fff}.nav-tabs>a.special{color:#fff;background-color:#396cad;border-bottom-color:#396cad}.nav-tabs>a.special:hover{background-color:#5386c6}.nav-tabs-lg>a{padding:3px 14px;margin:0 2px -1px}.nav-tabs-sm>a{padding:0 7px;margin:2px 2px -1px}header{padding-top:6px;background-color:#fff}header>div:not(:empty){display:block;margin:0;padding:0;border-bottom:solid #a6a6a6 1px;height:95px;overflow:visible}.menu-group{margin:0 5px 0 6px;display:inline-block;height:95px}.menu-content{height:79px;display:flow-root}.menu-content>a{display:inline-block}.menu-content>.btn,.menu-content>a>.btn{height:79px;text-align:center;margin:0 1px;padding:12px 5px;border:none;border-radius:0}.menu-content>.btn i,.menu-content>a>.btn i{font-size:20px;display:block;margin:0 auto 5px}.menu-content>.btn.btn-sm{height:26.33333333px;padding:0 5px}.menu-content>.btn.btn-sm i{display:inline-block;font-size:14px;margin:0}.menu-entry{text-align:left;height:26.33333333px;line-height:1;padding:.5rem 1rem}.menu-entry label{font-size:1.2rem;font-weight:400;margin:0}.menu-entry input[type=checkbox]{margin:0 2px;vertical-align:middle}.menu-legend{color:#777;height:16px;text-align:center;font-size:12px;padding:0 5px}.menu-group+.menu-group:before{margin-left:-6px;content:" ";border-left:solid 1px #e6e6e6;margin-top:10px;height:75px;position:absolute}.main-menu{display:flex}.main-menu .menu-group{width:50%}.main-menu .btn-sm{margin-top:6px}.filter-input{margin:4px 0}.filter-input .popover{top:27px;left:43px;display:block;max-width:none;opacity:.9}@media (max-width:767px){.filter-input .popover{top:16px;left:29px;right:2px}}.filter-input .popover .popover-content{max-height:500px;overflow-y:auto}.filter-input .popover .popover-content tr{cursor:pointer}.filter-input .popover .popover-content tr:hover{background-color:hsla(209,52%,84%,.5)!important}.connection-indicator{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;float:right;margin:5px;opacity:1;transition:all 1s linear}a.connection-indicator:focus,a.connection-indicator:hover{color:#fff;text-decoration:none;cursor:pointer}.connection-indicator:empty{display:none}.btn .connection-indicator{position:relative;top:-1px}.connection-indicator.fetching,.connection-indicator.init{background-color:#5bc0de}.connection-indicator.established{background-color:#5cb85c;opacity:0}.connection-indicator.error{background-color:#d9534f;transition:all .2s linear}.connection-indicator.offline{background-color:#f0ad4e;opacity:1}.flow-table{width:100%;overflow-y:scroll;overflow-x:hidden}.flow-table table{width:100%;table-layout:fixed}.flow-table thead tr{background-color:#f2f2f2;border-bottom:solid #bebebe 1px;line-height:23px}.flow-table th{font-weight:400;position:relative!important;padding-left:1px;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flow-table th.sort-asc,.flow-table th.sort-desc{background-color:#fafafa}.flow-table th.sort-asc:after,.flow-table th.sort-desc:after{font:normal normal normal 14px/1 FontAwesome;position:absolute;right:3px;top:3px;padding:2px;background-color:rgba(250,250,250,.8)}.flow-table th.sort-asc:after{content:"\f0de"}.flow-table th.sort-desc:after{content:"\f0dd"}.flow-table tr{cursor:pointer;background-color:#fff}.flow-table tr:nth-child(even){background-color:#f2f2f2}.flow-table tr.selected{background-color:#e0ebf5!important}.flow-table tr.selected.highlighted{background-color:#7bbefc!important}.flow-table tr.highlighted{background-color:#ffeb99}.flow-table tr.highlighted:nth-child(even){background-color:#ffe57f}.flow-table td{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.flow-table tr.intercepted:not(.has-response) .col-method,.flow-table tr.intercepted:not(.has-response) .col-path{color:#ff7f00}.flow-table tr.intercepted.has-response .col-size,.flow-table tr.intercepted.has-response .col-status,.flow-table tr.intercepted.has-response .col-time{color:#ff7f00}.flow-table .fa{line-height:inherit}.flow-table .col-tls{width:10px}.flow-table .col-tls-https{background-color:rgba(0,185,0,.5)}.flow-table .col-index{text-align:right;width:4ch}.flow-table .col-icon{width:32px}.flow-table .col-path .fa{margin-left:0;font-size:16px}.flow-table .col-path .fa-repeat{color:green}.flow-table .col-path .fa-pause{color:#ff7f00}.flow-table .col-path .fa-exclamation,.flow-table .col-path .fa-times{color:#8b0000}.flow-table .col-method{width:60px}.flow-table .col-version{width:80px}.flow-table .col-status{width:50px}.flow-table .col-size{width:70px}.flow-table .col-time{width:50px}.flow-table .col-timestamp{width:170px}.flow-table .col-comment{width:150px;padding-left:5px}.flow-table td.col-comment,.flow-table td.col-size,.flow-table td.col-time,.flow-table td.col-timestamp{text-align:right}.flow-table .col-quickactions{width:0;direction:rtl;overflow:hidden;background-color:inherit;font-size:20px}.flow-table .col-quickactions *{direction:ltr}.flow-table tr:hover .col-quickactions{overflow:visible}.flow-table .col-quickactions>div{height:32px;background-color:inherit;display:inline-flex;align-items:center}.flow-table .col-quickactions>div>a{margin-right:2px;height:32px;width:32px;border-radius:16px;text-align:center}.flow-table .col-quickactions>div>a:hover{background-color:rgba(0,0,0,.05)}.flow-table .col-quickactions .fa-play{transform:translate(1px,2px)}.flow-table .col-quickactions .fa-repeat{transform:translate(0,2px)}.flow-detail{width:100%;overflow:hidden;display:flex;flex-direction:column}.flow-detail nav{background-color:#f2f2f2}.flow-detail section{overflow-y:scroll;flex:1;padding:5px 12px 10px}.flow-detail section>footer{box-shadow:0 0 3px gray;padding:2px;margin:0;height:23px}.flow-detail .close-button{margin-top:2px;padding-left:10px;padding-right:7px;color:grey;font-size:15px;border:none}.flow-detail .close-button:hover{color:#000}.flow-detail .first-line{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;background-color:#428bca;color:#fff;margin:0 -8px 2px;padding:4px 8px;border-radius:5px;word-break:break-all;max-height:100px;overflow-y:auto}.flow-detail .contentview{margin:0 -12px;padding:0 12px}.flow-detail .contentview .controls{display:flex;align-items:center}.flow-detail .contentview .controls h5{flex:1;font-size:12px;font-weight:700;margin:10px 0}.flow-detail .contentview pre button:not(:only-child){margin-top:6px}.flow-detail hr{margin:0}.inline-input{display:inline;margin:0 -3px;padding:0 3px;border:solid transparent 1px}.inline-input:hover{box-shadow:0 0 0 1px rgba(0,0,0,.0125),0 2px 4px rgba(0,0,0,.05),0 2px 6px rgba(0,0,0,.025);background-color:rgba(255,255,255,.1)}.inline-input[placeholder]:empty:not(:focus-visible):before{content:attr(placeholder);color:#d3d3d3;font-style:italic}.inline-input[contenteditable]{outline-width:0;box-shadow:0 0 0 1px rgba(0,0,0,.05),0 2px 4px rgba(0,0,0,.2),0 2px 6px rgba(0,0,0,.1);background-color:rgba(255,255,255,.2)}.inline-input[contenteditable].has-warning{color:#ffb8b8}.certificate-table,.connection-table,.timing-table{width:100%;table-layout:fixed;word-break:break-all}.certificate-table td:nth-child(2),.connection-table td:nth-child(2),.timing-table td:nth-child(2){font-family:Menlo,Monaco,Consolas,"Courier New",monospace;width:70%}.certificate-table tr:not(:first-child),.connection-table tr:not(:first-child),.timing-table tr:not(:first-child){border-top:1px solid #f7f7f7}.certificate-table td,.connection-table td,.timing-table td{vertical-align:top}.connection-table td:first-child{padding-right:1em}.headers,.trailers{position:relative;min-height:2ex;overflow-wrap:break-word}.headers .kv-row,.trailers .kv-row{margin-bottom:.3em;max-height:12.4ex;overflow-y:auto}.headers .kv-key,.trailers .kv-key{font-weight:700}.headers .kv-value,.trailers .kv-value{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}.headers .inline-input,.trailers .inline-input{background-color:#fff}.headers .kv-add-row,.trailers .kv-add-row{opacity:0;color:#666;position:absolute;bottom:4px;right:4px;transition:all .1s ease-in-out}.headers:hover .kv-add-row,.trailers:hover .kv-add-row{opacity:1}.connection-table td,.timing-table td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}dl.cert-attributes{display:flex;flex-flow:row;flex-wrap:wrap;margin-bottom:0}dl.cert-attributes dd,dl.cert-attributes dt{text-overflow:ellipsis;overflow:hidden}dl.cert-attributes dt{flex:0 0 2em}dl.cert-attributes dd{flex:0 0 calc(100% - 2em)}.dns-request table td,.dns-request table th,.dns-response table td,.dns-response table th{padding-right:1rem}.flowview-image{text-align:center;padding:10px 0}.flowview-image img{max-width:100%;max-height:100%}.edit-flow-container{position:fixed;right:20px}.edit-flow{cursor:pointer;position:absolute;right:0;top:5px;height:40px;width:40px;border-radius:20px;z-index:10000;background-color:rgba(255,255,255,.7);border:solid 2px rgba(248,145,59,.7);text-align:center;font-size:22px;line-height:37px;transition:all .1s ease-in-out}.edit-flow:hover{background-color:rgba(239,108,0,.7);color:rgba(0,0,0,.8);border:solid 2px transparent}.eventlog{height:200px;flex:0 0 auto;display:flex;flex-direction:column}.eventlog>div{background-color:#f2f2f2;padding:0 5px;flex:0 0 auto;border-top:1px solid #aaa;cursor:row-resize}.eventlog>pre{flex:1 1 auto;margin:0;border-radius:0;overflow-x:auto;overflow-y:scroll;background-color:#fcfcfc}.eventlog .fa-close{cursor:pointer;float:right;color:grey;padding:3px 0;padding-left:10px}.eventlog .fa-close:hover{color:#000}.eventlog .btn-toggle{margin-top:-2px;margin-left:3px;padding:2px 2px;font-size:10px;line-height:10px;border-radius:2px}.eventlog .label{cursor:pointer;vertical-align:middle;display:inline-block;margin-top:-2px;margin-left:3px}footer{box-shadow:0 -1px 3px #d3d3d3;padding:0 0 4px 3px}footer .label{margin-right:3px}.CodeMirror{border:1px solid #ccc;height:auto!important}.CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor .CodeMirror-line::selection,.cm-fat-cursor .CodeMirror-line>span::selection,.cm-fat-cursor .CodeMirror-line>span>span::selection{background:0 0}.cm-fat-cursor .CodeMirror-line::-moz-selection,.cm-fat-cursor .CodeMirror-line>span::-moz-selection,.cm-fat-cursor .CodeMirror-line>span>span::-moz-selection{background:0 0}.cm-fat-cursor{caret-color:transparent}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:0;position:relative;z-index:0}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none;outline:0}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.contentview .header{font-weight:700}.contentview .highlight{font-weight:700}.contentview .offset{color:#00f}.contentview .codeeditor{margin-bottom:12px}.contentview .Token_Name_Tag{color:#006400}.contentview .Token_Literal_String{color:#b22222}.contentview .Token_Literal_Number{color:purple}.contentview .Token_Keyword_Constant{color:#00f}.modal-visible{display:block}.modal-dialog{overflow-y:initial!important}.modal-body{max-height:calc(100vh - 200px);overflow-y:auto}.dropdown-menu{margin:0!important;max-height:250px;overflow-y:scroll}.dropdown-menu>li>a{padding:3px 10px}.command-title{background-color:#f2f2f2;border:1px solid #aaa}.command-result{display:block;margin:0;background-color:#fcfcfc;height:100px;max-height:100px;overflow:auto}.command-suggestion{background-color:#9c9c9c}.argument-suggestion{background-color:hsla(209,52%,84%,.5)!important}.command>.popover{display:block;position:relative;max-width:none}.available-commands{overflow:auto}.wireguard-config{margin:1rem 0;display:flex;flex-wrap:wrap;column-gap:2rem;align-items:center}.wireguard-config>*{margin:0}.modes{padding:1em 2em;overflow-y:auto;height:100%;width:100vw}.modes h3{margin-bottom:10px}.modes .modes-category{padding-left:10px}.modes .green-left-border{border-left:10px solid #77c77a}.modes .gray-left-border{border-left:10px solid #b2b2b2}.modes .modes-container{display:flex;flex-direction:column;gap:25px}.modes .mode-title{font-size:16px;font-weight:600}.modes .mode-description{color:#b2b2b2;margin-top:-10px}.modes .mode-entry{text-align:left;display:flex;align-items:center;font-size:1.5rem;font-weight:400;margin:0}.modes .mode-entry input[type=checkbox]{margin:0 10px;vertical-align:middle;width:1.8rem;height:1.8rem}.modes .mode-entry p{margin:0}.modes .mode-status{margin-left:10px;margin-top:5px;font-weight:600}.modes .mode-local i{font-size:1.8rem;cursor:pointer}.modes .mode-local .processes-container{display:flex;flex-direction:row;align-items:center;gap:5px;margin-left:5px}.modes .mode-local .selected-processes{display:flex;flex-wrap:wrap;gap:5px;overflow:hidden}.modes .mode-local .selected-process{display:flex;flex-direction:row;gap:5px;background-color:#e0e0e0;padding:5px;border-radius:4px;height:30px;font-size:12px;font-weight:500;align-content:center;align-items:center}.modes .mode-local .selected-process>i{font-size:15px}.modes .mode-local .dropdown-container{display:flex;flex-direction:row;align-items:center}.modes .mode-local .local-dropdown{position:relative;width:200px}.modes .mode-local .local-dropdown .dropdown-header{padding:5px;border:1px solid #ccc;border-radius:4px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;margin-right:10px;height:30px}.modes .mode-local .local-dropdown input{border:none;flex:1;outline:0;color:#000}.modes .mode-local .local-dropdown .dropdown-list{width:100%;max-height:300px;overflow-y:auto;z-index:1;list-style:none;padding:0;margin-bottom:0}.modes .mode-local .local-dropdown .dropdown-item{display:flex;flex-direction:row;align-items:center;padding:8px 10px;margin:4px 0;border-radius:4px;cursor:pointer;transition:background-color .2s ease}.modes .mode-local .local-dropdown .dropdown-item.selected{background-color:#e0e0e0}.modes .mode-local .local-dropdown .dropdown-item:hover{background-color:#f0f0f0}.modes .mode-local .local-dropdown .process-details{display:flex;flex-direction:row;align-items:center}.modes .mode-local .local-dropdown .process-icon{margin-right:5px;margin-left:5px;color:#5f6368;width:25px;height:25px}.modes .mode-local .local-dropdown .process-name{font-weight:500;color:#333}.modes .mode-local .local-popover button{font-size:1rem}.modes .mode-local .local-popover i{font-size:1.5rem}@supports (anchor-name:--test){.modes .mode-local .local-popover>div{margin:0;position:absolute;left:0;top:calc(anchor(bottom) + 10px);justify-self:anchor-center;align-self:auto}}.modes .mode-local .local-popover>div{gap:.5rem;align-items:center}.modes .mode-local .local-popover>div:popover-open{display:block}.modes .mode-input{border:1px solid #ccc;margin-left:10px;border-radius:4px;min-width:120px;height:25px}.modes .mode-reverse-input{border:1px solid #ccc;margin-left:10px;margin-right:10px;border-radius:4px;min-width:70px;height:25px}.modes .mode-upstream-input{border:1px solid #ccc;margin-left:10px;margin-right:5px;border-radius:4px;min-width:70px;height:25px}.modes .mode-reverse-dropdown{margin:0 5px;border:1px solid #ccc;border-radius:4px;height:25px}.modes .mode-reverse-servers{display:flex;flex-direction:column;gap:10px}.modes .mode-reverse-add-server{margin-left:10px;display:flex;flex-direction:row;cursor:pointer;font-weight:500;opacity:.5;transition:all 50ms ease-in-out}.modes .mode-reverse-add-server:hover{opacity:1}.modes .mode-reverse-add-server i{font-size:2rem;margin-right:5px}.modes .mode-popover>button{background-color:transparent;border:none;cursor:pointer;font-size:2rem}@supports (anchor-name:--test){.modes .mode-popover>div{margin:0;position:absolute;left:calc(anchor(right) + 5px);align-self:anchor-center}}.modes .mode-popover>div{border:1px solid #ccc;border-radius:4px;padding:10px 15px;background-color:#f9f9f9;box-shadow:0 4px 8px rgba(0,0,0,.1);grid-template-columns:9em 1fr;grid-auto-rows:min-content;gap:.5rem;align-items:center}.modes .mode-popover>div:popover-open{display:grid}.modes .mode-popover>div>h4{text-align:center;grid-column:1/-1}.modes .mode-popover>div>.mode-input{text-align:right;background-color:#fff;margin:0} /*# sourceMappingURL=app.css.map */ diff --git a/mitmproxy/tools/web/static/app.js b/mitmproxy/tools/web/static/app.js index 11a11b85eb..a1d882229c 100644 --- a/mitmproxy/tools/web/static/app.js +++ b/mitmproxy/tools/web/static/app.js @@ -1,123 +1,137 @@ -(()=>{var cD=Object.create;var qc=Object.defineProperty,pD=Object.defineProperties,dD=Object.getOwnPropertyDescriptor,hD=Object.getOwnPropertyDescriptors,mD=Object.getOwnPropertyNames,Dg=Object.getOwnPropertySymbols,gD=Object.getPrototypeOf,Sw=Object.prototype.hasOwnProperty,Bb=Object.prototype.propertyIsEnumerable;var Cw=(e,t,n)=>t in e?qc(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,ke=(e,t)=>{for(var n in t||(t={}))Sw.call(t,n)&&Cw(e,n,t[n]);if(Dg)for(var n of Dg(t))Bb.call(t,n)&&Cw(e,n,t[n]);return e},Pt=(e,t)=>pD(e,hD(t)),Hb=e=>qc(e,"__esModule",{value:!0}),o=(e,t)=>qc(e,"name",{value:t,configurable:!0});var Ws=(e,t)=>{var n={};for(var l in e)Sw.call(e,l)&&t.indexOf(l)<0&&(n[l]=e[l]);if(e!=null&&Dg)for(var l of Dg(e))t.indexOf(l)<0&&Bb.call(e,l)&&(n[l]=e[l]);return n};var Ue=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Wb=(e,t)=>{Hb(e);for(var n in t)qc(e,n,{get:t[n],enumerable:!0})},vD=(e,t,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of mD(t))!Sw.call(e,l)&&l!=="default"&&qc(e,l,{get:()=>t[l],enumerable:!(n=dD(t,l))||n.enumerable});return e},fe=e=>vD(Hb(qc(e!=null?cD(gD(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var Vc=(e,t,n)=>(Cw(e,typeof t!="symbol"?t+"":t,n),n);var Ia=(e,t,n)=>new Promise((l,d)=>{var h=C=>{try{v(n.next(C))}catch(k){d(k)}},c=C=>{try{v(n.throw(C))}catch(k){d(k)}},v=C=>C.done?l(C.value):Promise.resolve(C.value).then(h,c);v((n=n.apply(e,t)).next())});var bw=Ue((cH,zb)=>{"use strict";var Ub=Object.getOwnPropertySymbols,yD=Object.prototype.hasOwnProperty,wD=Object.prototype.propertyIsEnumerable;function xD(e){if(e==null)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}o(xD,"toObject");function SD(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de",Object.getOwnPropertyNames(e)[0]==="5")return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;var l=Object.getOwnPropertyNames(t).map(function(h){return t[h]});if(l.join("")!=="0123456789")return!1;var d={};return"abcdefghijklmnopqrst".split("").forEach(function(h){d[h]=h}),Object.keys(Object.assign({},d)).join("")==="abcdefghijklmnopqrst"}catch(h){return!1}}o(SD,"shouldUseNative");zb.exports=SD()?Object.assign:function(e,t){for(var n,l=xD(e),d,h=1;h{"use strict";var Ew=bw(),Kc=60103,$b=60106;Et.Fragment=60107;Et.StrictMode=60108;Et.Profiler=60114;var jb=60109,qb=60110,Vb=60112;Et.Suspense=60113;var Kb=60115,Gb=60116;typeof Symbol=="function"&&Symbol.for&&(Co=Symbol.for,Kc=Co("react.element"),$b=Co("react.portal"),Et.Fragment=Co("react.fragment"),Et.StrictMode=Co("react.strict_mode"),Et.Profiler=Co("react.profiler"),jb=Co("react.provider"),qb=Co("react.context"),Vb=Co("react.forward_ref"),Et.Suspense=Co("react.suspense"),Kb=Co("react.memo"),Gb=Co("react.lazy"));var Co,Yb=typeof Symbol=="function"&&Symbol.iterator;function CD(e){return e===null||typeof e!="object"?null:(e=Yb&&e[Yb]||e["@@iterator"],typeof e=="function"?e:null)}o(CD,"y");function Yd(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n{"use strict";oE.exports=iE()});var cE=Ue(Rt=>{"use strict";var Yc,Xd,Fg,Pw;typeof performance=="object"&&typeof performance.now=="function"?(sE=performance,Rt.unstable_now=function(){return sE.now()}):(Ow=Date,lE=Ow.now(),Rt.unstable_now=function(){return Ow.now()-lE});var sE,Ow,lE;typeof window=="undefined"||typeof MessageChannel!="function"?(Xc=null,Mw=null,Aw=o(function(){if(Xc!==null)try{var e=Rt.unstable_now();Xc(!0,e),Xc=null}catch(t){throw setTimeout(Aw,0),t}},"w"),Yc=o(function(e){Xc!==null?setTimeout(Yc,0,e):(Xc=e,setTimeout(Aw,0))},"f"),Xd=o(function(e,t){Mw=setTimeout(e,t)},"g"),Fg=o(function(){clearTimeout(Mw)},"h"),Rt.unstable_shouldYield=function(){return!1},Pw=Rt.unstable_forceFrameRate=function(){}):(aE=window.setTimeout,uE=window.clearTimeout,typeof console!="undefined"&&(fE=window.cancelAnimationFrame,typeof window.requestAnimationFrame!="function"&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),typeof fE!="function"&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")),Qd=!1,Zd=null,Bg=-1,Dw=5,Rw=0,Rt.unstable_shouldYield=function(){return Rt.unstable_now()>=Rw},Pw=o(function(){},"k"),Rt.unstable_forceFrameRate=function(e){0>e||125>>1,d=e[l];if(d!==void 0&&0Ug(c,n))C!==void 0&&0>Ug(C,c)?(e[l]=C,e[v]=n,l=v):(e[l]=c,e[h]=n,l=h);else if(C!==void 0&&0>Ug(C,n))e[l]=C,e[v]=n,l=v;else break e}}return t}return null}o(Wg,"K");function Ug(e,t){var n=e.sortIndex-t.sortIndex;return n!==0?n:e.id-t.id}o(Ug,"I");var Us=[],Fa=[],kD=1,bo=null,Yn=3,zg=!1,df=!1,Jd=!1;function Bw(e){for(var t=os(Fa);t!==null;){if(t.callback===null)Wg(Fa);else if(t.startTime<=e)Wg(Fa),t.sortIndex=t.expirationTime,Fw(Us,t);else break;t=os(Fa)}}o(Bw,"T");function Hw(e){if(Jd=!1,Bw(e),!df)if(os(Us)!==null)df=!0,Yc(Ww);else{var t=os(Fa);t!==null&&Xd(Hw,t.startTime-e)}}o(Hw,"U");function Ww(e,t){df=!1,Jd&&(Jd=!1,Fg()),zg=!0;var n=Yn;try{for(Bw(t),bo=os(Us);bo!==null&&(!(bo.expirationTime>t)||e&&!Rt.unstable_shouldYield());){var l=bo.callback;if(typeof l=="function"){bo.callback=null,Yn=bo.priorityLevel;var d=l(bo.expirationTime<=t);t=Rt.unstable_now(),typeof d=="function"?bo.callback=d:bo===os(Us)&&Wg(Us),Bw(t)}else Wg(Us);bo=os(Us)}if(bo!==null)var h=!0;else{var c=os(Fa);c!==null&&Xd(Hw,c.startTime-t),h=!1}return h}finally{bo=null,Yn=n,zg=!1}}o(Ww,"V");var ND=Pw;Rt.unstable_IdlePriority=5;Rt.unstable_ImmediatePriority=1;Rt.unstable_LowPriority=4;Rt.unstable_NormalPriority=3;Rt.unstable_Profiling=null;Rt.unstable_UserBlockingPriority=2;Rt.unstable_cancelCallback=function(e){e.callback=null};Rt.unstable_continueExecution=function(){df||zg||(df=!0,Yc(Ww))};Rt.unstable_getCurrentPriorityLevel=function(){return Yn};Rt.unstable_getFirstCallbackNode=function(){return os(Us)};Rt.unstable_next=function(e){switch(Yn){case 1:case 2:case 3:var t=3;break;default:t=Yn}var n=Yn;Yn=t;try{return e()}finally{Yn=n}};Rt.unstable_pauseExecution=function(){};Rt.unstable_requestPaint=ND;Rt.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=Yn;Yn=e;try{return t()}finally{Yn=n}};Rt.unstable_scheduleCallback=function(e,t,n){var l=Rt.unstable_now();switch(typeof n=="object"&&n!==null?(n=n.delay,n=typeof n=="number"&&0l?(e.sortIndex=n,Fw(Fa,e),os(Us)===null&&e===os(Fa)&&(Jd?Fg():Jd=!0,Xd(Hw,n-l))):(e.sortIndex=d,Fw(Us,e),df||zg||(df=!0,Yc(Ww))),e};Rt.unstable_wrapCallback=function(e){var t=Yn;return function(){var n=Yn;Yn=t;try{return e.apply(this,arguments)}finally{Yn=n}}}});var dE=Ue((mH,pE)=>{"use strict";pE.exports=cE()});var JT=Ue(Lo=>{"use strict";var $g=Oe(),hr=bw(),Tn=dE();function we(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;nt}return!1}o(MD,"na");function vi(e,t,n,l,d,h,c){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=l,this.attributeNamespace=d,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=h,this.removeEmptyString=c}o(vi,"B");var Rn={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Rn[e]=new vi(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Rn[t]=new vi(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Rn[e]=new vi(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Rn[e]=new vi(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Rn[e]=new vi(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Rn[e]=new vi(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Rn[e]=new vi(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Rn[e]=new vi(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Rn[e]=new vi(e,5,!1,e.toLowerCase(),null,!1,!1)});var Uw=/[\-:]([a-z])/g;function zw(e){return e[1].toUpperCase()}o(zw,"pa");"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Uw,zw);Rn[t]=new vi(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Uw,zw);Rn[t]=new vi(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Uw,zw);Rn[t]=new vi(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Rn[e]=new vi(e,1,!1,e.toLowerCase(),null,!1,!1)});Rn.xlinkHref=new vi("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Rn[e]=new vi(e,1,!1,e.toLowerCase(),null,!0,!0)});function $w(e,t,n,l){var d=Rn.hasOwnProperty(t)?Rn[t]:null,h=d!==null?d.type===0:l?!1:!(!(2v||d[c]!==h[v])return` -`+d[c].replace(" at new "," at ");while(1<=c&&0<=v);break}}}finally{Jw=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?oh(e):""}o(Kg,"Pa");function AD(e){switch(e.tag){case 5:return oh(e.type);case 16:return oh("Lazy");case 13:return oh("Suspense");case 19:return oh("SuspenseList");case 0:case 2:case 15:return e=Kg(e.type,!1),e;case 11:return e=Kg(e.type.render,!1),e;case 22:return e=Kg(e.type._render,!1),e;case 1:return e=Kg(e.type,!0),e;default:return""}}o(AD,"Qa");function Zc(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Ba:return"Fragment";case gf:return"Portal";case rh:return"Profiler";case jw:return"StrictMode";case nh:return"Suspense";case qg:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Vw:return(e.displayName||"Context")+".Consumer";case qw:return(e._context.displayName||"Context")+".Provider";case jg:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(t!==""?"ForwardRef("+t+")":"ForwardRef");case Vg:return Zc(e.type);case Gw:return Zc(e._render);case Kw:t=e._payload,e=e._init;try{return Zc(e(t))}catch(n){}}return null}o(Zc,"Ra");function Ha(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}o(Ha,"Sa");function xE(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}o(xE,"Ta");function DD(e){var t=xE(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),l=""+e[t];if(!e.hasOwnProperty(t)&&typeof n!="undefined"&&typeof n.get=="function"&&typeof n.set=="function"){var d=n.get,h=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return d.call(this)},set:function(c){l=""+c,h.call(this,c)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return l},setValue:function(c){l=""+c},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}o(DD,"Ua");function Gg(e){e._valueTracker||(e._valueTracker=DD(e))}o(Gg,"Va");function SE(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),l="";return e&&(l=xE(e)?e.checked?"true":"false":e.value),e=l,e!==n?(t.setValue(e),!0):!1}o(SE,"Wa");function Yg(e){if(e=e||(typeof document!="undefined"?document:void 0),typeof e=="undefined")return null;try{return e.activeElement||e.body}catch(t){return e.body}}o(Yg,"Xa");function e1(e,t){var n=t.checked;return hr({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}o(e1,"Ya");function CE(e,t){var n=t.defaultValue==null?"":t.defaultValue,l=t.checked!=null?t.checked:t.defaultChecked;n=Ha(t.value!=null?t.value:n),e._wrapperState={initialChecked:l,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}o(CE,"Za");function bE(e,t){t=t.checked,t!=null&&$w(e,"checked",t,!1)}o(bE,"$a");function t1(e,t){bE(e,t);var n=Ha(t.value),l=t.type;if(n!=null)l==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(l==="submit"||l==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?r1(e,t.type,n):t.hasOwnProperty("defaultValue")&&r1(e,t.type,Ha(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}o(t1,"ab");function EE(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var l=t.type;if(!(l!=="submit"&&l!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}o(EE,"cb");function r1(e,t,n){(t!=="number"||Yg(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}o(r1,"bb");function RD(e){var t="";return $g.Children.forEach(e,function(n){n!=null&&(t+=n)}),t}o(RD,"db");function n1(e,t){return e=hr({children:void 0},t),(t=RD(t.children))&&(e.children=t),e}o(n1,"eb");function Jc(e,t,n,l){if(e=e.options,t){t={};for(var d=0;d=n.length))throw Error(we(93));n=n[0]}t=n}t==null&&(t=""),n=t}e._wrapperState={initialValue:Ha(n)}}o(_E,"hb");function TE(e,t){var n=Ha(t.value),l=Ha(t.defaultValue);n!=null&&(n=""+n,n!==e.value&&(e.value=n),t.defaultValue==null&&e.defaultValue!==n&&(e.defaultValue=n)),l!=null&&(e.defaultValue=""+l)}o(TE,"ib");function kE(e){var t=e.textContent;t===e._wrapperState.initialValue&&t!==""&&t!==null&&(e.value=t)}o(kE,"jb");var o1={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};function NE(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}o(NE,"lb");function s1(e,t){return e==null||e==="http://www.w3.org/1999/xhtml"?NE(t):e==="http://www.w3.org/2000/svg"&&t==="foreignObject"?"http://www.w3.org/1999/xhtml":e}o(s1,"mb");var Xg,LE=function(e){return typeof MSApp!="undefined"&&MSApp.execUnsafeLocalFunction?function(t,n,l,d){MSApp.execUnsafeLocalFunction(function(){return e(t,n,l,d)})}:e}(function(e,t){if(e.namespaceURI!==o1.svg||"innerHTML"in e)e.innerHTML=t;else{for(Xg=Xg||document.createElement("div"),Xg.innerHTML=""+t.valueOf().toString()+"",t=Xg.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function sh(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}o(sh,"pb");var lh={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ID=["Webkit","ms","Moz","O"];Object.keys(lh).forEach(function(e){ID.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),lh[t]=lh[e]})});function PE(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||lh.hasOwnProperty(e)&&lh[e]?(""+t).trim():t+"px"}o(PE,"sb");function OE(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var l=n.indexOf("--")===0,d=PE(n,t[n],l);n==="float"&&(n="cssFloat"),l?e.setProperty(n,d):e[n]=d}}o(OE,"tb");var FD=hr({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function l1(e,t){if(t){if(FD[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(we(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(we(60));if(!(typeof t.dangerouslySetInnerHTML=="object"&&"__html"in t.dangerouslySetInnerHTML))throw Error(we(61))}if(t.style!=null&&typeof t.style!="object")throw Error(we(62))}}o(l1,"vb");function a1(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}o(a1,"wb");function u1(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}o(u1,"xb");var f1=null,ep=null,tp=null;function ME(e){if(e=_h(e)){if(typeof f1!="function")throw Error(we(280));var t=e.stateNode;t&&(t=vv(t),f1(e.stateNode,e.type,t))}}o(ME,"Bb");function AE(e){ep?tp?tp.push(e):tp=[e]:ep=e}o(AE,"Eb");function DE(){if(ep){var e=ep,t=tp;if(tp=ep=null,ME(e),t)for(e=0;el?0:1<n;n++)t.push(e);return t}o(b1,"Zc");function nv(e,t,n){e.pendingLanes|=t;var l=t-1;e.suspendedLanes&=l,e.pingedLanes&=l,e=e.eventTimes,t=31-$a(t),e[t]=n}o(nv,"$c");var $a=Math.clz32?Math.clz32:JD,QD=Math.log,ZD=Math.LN2;function JD(e){return e===0?32:31-(QD(e)/ZD|0)|0}o(JD,"ad");var eR=Tn.unstable_UserBlockingPriority,tR=Tn.unstable_runWithPriority,iv=!0;function rR(e,t,n,l){vf||p1();var d=E1,h=vf;vf=!0;try{RE(d,e,t,n,l)}finally{(vf=h)||h1()}}o(rR,"gd");function nR(e,t,n,l){tR(eR,E1.bind(null,e,t,n,l))}o(nR,"id");function E1(e,t,n,l){if(iv){var d;if((d=(t&4)==0)&&0=yh),l_=String.fromCharCode(32),a_=!1;function u_(e,t){switch(e){case"keyup":return TR.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}o(u_,"ge");function f_(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}o(f_,"he");var lp=!1;function NR(e,t){switch(e){case"compositionend":return f_(t);case"keypress":return t.which!==32?null:(a_=!0,l_);case"textInput":return e=t.data,e===l_&&a_?null:e;default:return null}}o(NR,"je");function LR(e,t){if(lp)return e==="compositionend"||!M1&&u_(e,t)?(e=t_(),ov=T1=ja=null,lp=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=l}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=g_(n)}}o(v_,"Le");function y_(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?y_(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}o(y_,"Me");function w_(){for(var e=window,t=Yg();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch(l){n=!1}if(n)e=t.contentWindow;else break;t=Yg(e.document)}return t}o(w_,"Ne");function D1(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}o(D1,"Oe");var HR=Ll&&"documentMode"in document&&11>=document.documentMode,ap=null,R1=null,Ch=null,I1=!1;function x_(e,t,n){var l=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;I1||ap==null||ap!==Yg(l)||(l=ap,"selectionStart"in l&&D1(l)?l={start:l.selectionStart,end:l.selectionEnd}:(l=(l.ownerDocument&&l.ownerDocument.defaultView||window).getSelection(),l={anchorNode:l.anchorNode,anchorOffset:l.anchorOffset,focusNode:l.focusNode,focusOffset:l.focusOffset}),Ch&&Sh(Ch,l)||(Ch=l,l=dv(R1,"onSelect"),0dp||(e.current=$1[dp],$1[dp]=null,dp--)}o(fr,"H");function _r(e,t){dp++,$1[dp]=e.current,e.current=t}o(_r,"I");var Ka={},Xn=Va(Ka),Ri=Va(!1),xf=Ka;function hp(e,t){var n=e.type.contextTypes;if(!n)return Ka;var l=e.stateNode;if(l&&l.__reactInternalMemoizedUnmaskedChildContext===t)return l.__reactInternalMemoizedMaskedChildContext;var d={},h;for(h in n)d[h]=t[h];return l&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=d),d}o(hp,"Ef");function Ii(e){return e=e.childContextTypes,e!=null}o(Ii,"Ff");function yv(){fr(Ri),fr(Xn)}o(yv,"Gf");function R_(e,t,n){if(Xn.current!==Ka)throw Error(we(168));_r(Xn,t),_r(Ri,n)}o(R_,"Hf");function I_(e,t,n){var l=e.stateNode;if(e=t.childContextTypes,typeof l.getChildContext!="function")return n;l=l.getChildContext();for(var d in l)if(!(d in e))throw Error(we(108,Zc(t)||"Unknown",d));return hr({},n,l)}o(I_,"If");function wv(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Ka,xf=Xn.current,_r(Xn,e),_r(Ri,Ri.current),!0}o(wv,"Jf");function F_(e,t,n){var l=e.stateNode;if(!l)throw Error(we(169));n?(e=I_(e,t,xf),l.__reactInternalMemoizedMergedChildContext=e,fr(Ri),fr(Xn),_r(Xn,e)):fr(Ri),_r(Ri,n)}o(F_,"Kf");var j1=null,Sf=null,zR=Tn.unstable_runWithPriority,q1=Tn.unstable_scheduleCallback,V1=Tn.unstable_cancelCallback,$R=Tn.unstable_shouldYield,B_=Tn.unstable_requestPaint,K1=Tn.unstable_now,jR=Tn.unstable_getCurrentPriorityLevel,xv=Tn.unstable_ImmediatePriority,H_=Tn.unstable_UserBlockingPriority,W_=Tn.unstable_NormalPriority,U_=Tn.unstable_LowPriority,z_=Tn.unstable_IdlePriority,G1={},qR=B_!==void 0?B_:function(){},Pl=null,Sv=null,Y1=!1,$_=K1(),Qn=1e4>$_?K1:function(){return K1()-$_};function mp(){switch(jR()){case xv:return 99;case H_:return 98;case W_:return 97;case U_:return 96;case z_:return 95;default:throw Error(we(332))}}o(mp,"eg");function j_(e){switch(e){case 99:return xv;case 98:return H_;case 97:return W_;case 96:return U_;case 95:return z_;default:throw Error(we(332))}}o(j_,"fg");function Cf(e,t){return e=j_(e),zR(e,t)}o(Cf,"gg");function Th(e,t,n){return e=j_(e),q1(e,t,n)}o(Th,"hg");function $s(){if(Sv!==null){var e=Sv;Sv=null,V1(e)}q_()}o($s,"ig");function q_(){if(!Y1&&Pl!==null){Y1=!0;var e=0;try{var t=Pl;Cf(99,function(){for(;epe?(me=ne,ne=null):me=ne.sibling;var xe=B(R,ne,I[pe],G);if(xe===null){ne===null&&(ne=me);break}e&&ne&&xe.alternate===null&&t(R,ne),A=h(xe,A,pe),se===null?K=xe:se.sibling=xe,se=xe,ne=me}if(pe===I.length)return n(R,ne),K;if(ne===null){for(;pepe?(me=ne,ne=null):me=ne.sibling;var Ve=B(R,ne,xe.value,G);if(Ve===null){ne===null&&(ne=me);break}e&&ne&&Ve.alternate===null&&t(R,ne),A=h(Ve,A,pe),se===null?K=Ve:se.sibling=Ve,se=Ve,ne=me}if(xe.done)return n(R,ne),K;if(ne===null){for(;!xe.done;pe++,xe=I.next())xe=j(R,xe.value,G),xe!==null&&(A=h(xe,A,pe),se===null?K=xe:se.sibling=xe,se=xe);return K}for(ne=l(R,ne);!xe.done;pe++,xe=I.next())xe=X(ne,R,pe,xe.value,G),xe!==null&&(e&&xe.alternate!==null&&ne.delete(xe.key===null?pe:xe.key),A=h(xe,A,pe),se===null?K=xe:se.sibling=xe,se=xe);return e&&ne.forEach(function(tt){return t(R,tt)}),K}return o(Z,"w"),function(R,A,I,G){var K=typeof I=="object"&&I!==null&&I.type===Ba&&I.key===null;K&&(I=I.props.children);var se=typeof I=="object"&&I!==null;if(se)switch(I.$$typeof){case th:e:{for(se=I.key,K=A;K!==null;){if(K.key===se){switch(K.tag){case 7:if(I.type===Ba){n(R,K.sibling),A=d(K,I.props.children),A.return=R,R=A;break e}break;default:if(K.elementType===I.type){n(R,K.sibling),A=d(K,I.props),A.ref=Nh(R,K,I),A.return=R,R=A;break e}}n(R,K);break}else t(R,K);K=K.sibling}I.type===Ba?(A=_p(I.props.children,R.mode,G,I.key),A.return=R,R=A):(G=Vv(I.type,I.key,I.props,null,R.mode,G),G.ref=Nh(R,A,I),G.return=R,R=G)}return c(R);case gf:e:{for(K=I.key;A!==null;){if(A.key===K)if(A.tag===4&&A.stateNode.containerInfo===I.containerInfo&&A.stateNode.implementation===I.implementation){n(R,A.sibling),A=d(A,I.children||[]),A.return=R,R=A;break e}else{n(R,A);break}else t(R,A);A=A.sibling}A=Ix(I,R.mode,G),A.return=R,R=A}return c(R)}if(typeof I=="string"||typeof I=="number")return I=""+I,A!==null&&A.tag===6?(n(R,A.sibling),A=d(A,I),A.return=R,R=A):(n(R,A),A=Rx(I,R.mode,G),A.return=R,R=A),c(R);if(kv(I))return J(R,A,I,G);if(ih(I))return Z(R,A,I,G);if(se&&Nv(R,I),typeof I=="undefined"&&!K)switch(R.tag){case 1:case 22:case 0:case 11:case 15:throw Error(we(152,Zc(R.type)||"Component"))}return n(R,A)}}o(eT,"Sg");var Lv=eT(!0),tT=eT(!1),Lh={},js=Va(Lh),Ph=Va(Lh),Oh=Va(Lh);function bf(e){if(e===Lh)throw Error(we(174));return e}o(bf,"dh");function ex(e,t){switch(_r(Oh,t),_r(Ph,e),_r(js,Lh),e=t.nodeType,e){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:s1(null,"");break;default:e=e===8?t.parentNode:t,t=e.namespaceURI||null,e=e.tagName,t=s1(t,e)}fr(js),_r(js,t)}o(ex,"eh");function yp(){fr(js),fr(Ph),fr(Oh)}o(yp,"fh");function rT(e){bf(Oh.current);var t=bf(js.current),n=s1(t,e.type);t!==n&&(_r(Ph,e),_r(js,n))}o(rT,"gh");function tx(e){Ph.current===e&&(fr(js),fr(Ph))}o(tx,"hh");var Tr=Va(0);function Pv(e){for(var t=e;t!==null;){if(t.tag===13){var n=t.memoizedState;if(n!==null&&(n=n.dehydrated,n===null||n.data==="$?"||n.data==="$!"))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&64)!=0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}o(Pv,"ih");var Ol=null,Qa=null,qs=!1;function nT(e,t){var n=No(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.flags=8,e.lastEffect!==null?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}o(nT,"mh");function iT(e,t){switch(e.tag){case 5:var n=e.type;return t=t.nodeType!==1||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t,t!==null?(e.stateNode=t,!0):!1;case 6:return t=e.pendingProps===""||t.nodeType!==3?null:t,t!==null?(e.stateNode=t,!0):!1;case 13:return!1;default:return!1}}o(iT,"oh");function rx(e){if(qs){var t=Qa;if(t){var n=t;if(!iT(e,t)){if(t=fp(n.nextSibling),!t||!iT(e,t)){e.flags=e.flags&-1025|2,qs=!1,Ol=e;return}nT(Ol,n)}Ol=e,Qa=fp(t.firstChild)}else e.flags=e.flags&-1025|2,qs=!1,Ol=e}}o(rx,"ph");function oT(e){for(e=e.return;e!==null&&e.tag!==5&&e.tag!==3&&e.tag!==13;)e=e.return;Ol=e}o(oT,"qh");function Ov(e){if(e!==Ol)return!1;if(!qs)return oT(e),qs=!0,!1;var t=e.type;if(e.tag!==5||t!=="head"&&t!=="body"&&!W1(t,e.memoizedProps))for(t=Qa;t;)nT(e,t),t=fp(t.nextSibling);if(oT(e),e.tag===13){if(e=e.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(we(317));e:{for(e=e.nextSibling,t=0;e;){if(e.nodeType===8){var n=e.data;if(n==="/$"){if(t===0){Qa=fp(e.nextSibling);break e}t--}else n!=="$"&&n!=="$!"&&n!=="$?"||t++}e=e.nextSibling}Qa=null}}else Qa=Ol?fp(e.stateNode.nextSibling):null;return!0}o(Ov,"rh");function nx(){Qa=Ol=null,qs=!1}o(nx,"sh");var wp=[];function ix(){for(var e=0;eh))throw Error(we(301));h+=1,In=Zn=null,t.updateQueue=null,Mh.current=XR,e=n(l,d)}while(Dh)}if(Mh.current=Iv,t=Zn!==null&&Zn.next!==null,Ah=0,In=Zn=Fr=null,Mv=!1,t)throw Error(we(300));return e}o(sx,"Ch");function Ef(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return In===null?Fr.memoizedState=In=e:In=In.next=e,In}o(Ef,"Hh");function _f(){if(Zn===null){var e=Fr.alternate;e=e!==null?e.memoizedState:null}else e=Zn.next;var t=In===null?Fr.memoizedState:In.next;if(t!==null)In=t,Zn=e;else{if(e===null)throw Error(we(310));Zn=e,e={memoizedState:Zn.memoizedState,baseState:Zn.baseState,baseQueue:Zn.baseQueue,queue:Zn.queue,next:null},In===null?Fr.memoizedState=In=e:In=In.next=e}return In}o(_f,"Ih");function Vs(e,t){return typeof t=="function"?t(e):t}o(Vs,"Jh");function Rh(e){var t=_f(),n=t.queue;if(n===null)throw Error(we(311));n.lastRenderedReducer=e;var l=Zn,d=l.baseQueue,h=n.pending;if(h!==null){if(d!==null){var c=d.next;d.next=h.next,h.next=c}l.baseQueue=d=h,n.pending=null}if(d!==null){d=d.next,l=l.baseState;var v=c=h=null,C=d;do{var k=C.lane;if((Ah&k)===k)v!==null&&(v=v.next={lane:0,action:C.action,eagerReducer:C.eagerReducer,eagerState:C.eagerState,next:null}),l=C.eagerReducer===e?C.eagerState:e(l,C.action);else{var O={lane:k,action:C.action,eagerReducer:C.eagerReducer,eagerState:C.eagerState,next:null};v===null?(c=v=O,h=l):v=v.next=O,Fr.lanes|=k,Hh|=k}C=C.next}while(C!==null&&C!==d);v===null?h=l:v.next=c,Eo(l,t.memoizedState)||(ls=!0),t.memoizedState=l,t.baseState=h,t.baseQueue=v,n.lastRenderedState=l}return[t.memoizedState,n.dispatch]}o(Rh,"Kh");function Ih(e){var t=_f(),n=t.queue;if(n===null)throw Error(we(311));n.lastRenderedReducer=e;var l=n.dispatch,d=n.pending,h=t.memoizedState;if(d!==null){n.pending=null;var c=d=d.next;do h=e(h,c.action),c=c.next;while(c!==d);Eo(h,t.memoizedState)||(ls=!0),t.memoizedState=h,t.baseQueue===null&&(t.baseState=h),n.lastRenderedState=h}return[h,l]}o(Ih,"Lh");function sT(e,t,n){var l=t._getVersion;l=l(t._source);var d=t._workInProgressVersionPrimary;if(d!==null?e=d===l:(e=e.mutableReadLanes,(e=(Ah&e)===e)&&(t._workInProgressVersionPrimary=l,wp.push(t))),e)return n(t._source);throw wp.push(t),Error(we(350))}o(sT,"Mh");function lT(e,t,n,l){var d=yi;if(d===null)throw Error(we(349));var h=t._getVersion,c=h(t._source),v=Mh.current,C=v.useState(function(){return sT(d,t,n)}),k=C[1],O=C[0];C=In;var j=e.memoizedState,B=j.refs,X=B.getSnapshot,J=j.source;j=j.subscribe;var Z=Fr;return e.memoizedState={refs:B,source:t,subscribe:l},v.useEffect(function(){B.getSnapshot=n,B.setSnapshot=k;var R=h(t._source);if(!Eo(c,R)){R=n(t._source),Eo(O,R)||(k(R),R=Ja(Z),d.mutableReadLanes|=R&d.pendingLanes),R=d.mutableReadLanes,d.entangledLanes|=R;for(var A=d.entanglements,I=R;0n?98:n,function(){e(!0)}),Cf(97<\/script>",e=e.removeChild(e.firstChild)):typeof l.is=="string"?e=c.createElement(n,{is:l.is}):(e=c.createElement(n),n==="select"&&(c=e,l.multiple?c.multiple=!0:l.size&&(c.size=l.size))):e=c.createElementNS(e,n),e[qa]=t,e[gv]=l,NT(e,t,!1,!1),t.stateNode=e,c=a1(n,l),n){case"dialog":ur("cancel",e),ur("close",e),d=l;break;case"iframe":case"object":case"embed":ur("load",e),d=l;break;case"video":case"audio":for(d=0;dTx&&(t.flags|=64,h=!0,Bh(l,!1),t.lanes=33554432)}else{if(!h)if(e=Pv(c),e!==null){if(t.flags|=64,h=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Bh(l,!0),l.tail===null&&l.tailMode==="hidden"&&!c.alternate&&!qs)return t=t.lastEffect=l.lastEffect,t!==null&&(t.nextEffect=null),null}else 2*Qn()-l.renderingStartTime>Tx&&n!==1073741824&&(t.flags|=64,h=!0,Bh(l,!1),t.lanes=33554432);l.isBackwards?(c.sibling=t.child,t.child=c):(n=l.last,n!==null?n.sibling=c:t.child=c,l.last=c)}return l.tail!==null?(n=l.tail,l.rendering=n,l.tail=n.sibling,l.lastEffect=t.lastEffect,l.renderingStartTime=Qn(),n.sibling=null,t=Tr.current,_r(Tr,h?t&1|2:t&1),n):null;case 23:case 24:return Mx(),e!==null&&e.memoizedState!==null!=(t.memoizedState!==null)&&l.mode!=="unstable-defer-without-hiding"&&(t.flags|=4),null}throw Error(we(156,t.tag))}o(ZR,"Gi");function JR(e){switch(e.tag){case 1:Ii(e.type)&&yv();var t=e.flags;return t&4096?(e.flags=t&-4097|64,e):null;case 3:if(yp(),fr(Ri),fr(Xn),ix(),t=e.flags,(t&64)!=0)throw Error(we(285));return e.flags=t&-4097|64,e;case 5:return tx(e),null;case 13:return fr(Tr),t=e.flags,t&4096?(e.flags=t&-4097|64,e):null;case 19:return fr(Tr),null;case 4:return yp(),null;case 10:return Q1(e),null;case 23:case 24:return Mx(),null;default:return null}}o(JR,"Li");function gx(e,t){try{var n="",l=t;do n+=AD(l),l=l.return;while(l);var d=n}catch(h){d=` +(()=>{var PI=Object.create;var cv=Object.defineProperty;var LI=Object.getOwnPropertyDescriptor;var MI=Object.getOwnPropertyNames;var OI=Object.getPrototypeOf,RI=Object.prototype.hasOwnProperty;var i=(e,t)=>cv(e,"name",{value:t,configurable:!0});var rt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),xb=(e,t)=>{for(var n in t)cv(e,n,{get:t[n],enumerable:!0})},DI=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of MI(t))!RI.call(e,l)&&l!==n&&cv(e,l,{get:()=>t[l],enumerable:!(s=LI(t,l))||s.enumerable});return e};var pe=(e,t,n)=>(n=e!=null?PI(OI(e)):{},DI(t||!e||!e.__esModule?cv(n,"default",{value:e,enumerable:!0}):n,e));var Ob=rt(mt=>{"use strict";var Lh=Symbol.for("react.element"),II=Symbol.for("react.portal"),FI=Symbol.for("react.fragment"),BI=Symbol.for("react.strict_mode"),HI=Symbol.for("react.profiler"),zI=Symbol.for("react.provider"),UI=Symbol.for("react.context"),WI=Symbol.for("react.forward_ref"),$I=Symbol.for("react.suspense"),VI=Symbol.for("react.memo"),qI=Symbol.for("react.lazy"),Cb=Symbol.iterator;function jI(e){return e===null||typeof e!="object"?null:(e=Cb&&e[Cb]||e["@@iterator"],typeof e=="function"?e:null)}i(jI,"A");var bb={isMounted:i(function(){return!1},"isMounted"),enqueueForceUpdate:i(function(){},"enqueueForceUpdate"),enqueueReplaceState:i(function(){},"enqueueReplaceState"),enqueueSetState:i(function(){},"enqueueSetState")},Tb=Object.assign,kb={};function Pd(e,t,n){this.props=e,this.context=t,this.refs=kb,this.updater=n||bb}i(Pd,"E");Pd.prototype.isReactComponent={};Pd.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Pd.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Nb(){}i(Nb,"F");Nb.prototype=Pd.prototype;function t1(e,t,n){this.props=e,this.context=t,this.refs=kb,this.updater=n||bb}i(t1,"G");var r1=t1.prototype=new Nb;r1.constructor=t1;Tb(r1,Pd.prototype);r1.isPureReactComponent=!0;var _b=Array.isArray,Ab=Object.prototype.hasOwnProperty,n1={current:null},Pb={key:!0,ref:!0,__self:!0,__source:!0};function Lb(e,t,n){var s,l={},h=null,d=null;if(t!=null)for(s in t.ref!==void 0&&(d=t.ref),t.key!==void 0&&(h=""+t.key),t)Ab.call(t,s)&&!Pb.hasOwnProperty(s)&&(l[s]=t[s]);var v=arguments.length-2;if(v===1)l.children=n;else if(1{"use strict";Rb.exports=Ob()});var Vb=rt(tr=>{"use strict";function l1(e,t){var n=e.length;e.push(t);e:for(;0>>1,l=e[s];if(0>>1;shv(v,n))Shv(b,v)?(e[s]=b,e[S]=n,s=S):(e[s]=v,e[d]=n,s=d);else if(Shv(b,n))e[s]=b,e[S]=n,s=S;else break e}}return t}i(gv,"k");function hv(e,t){var n=e.sortIndex-t.sortIndex;return n!==0?n:e.id-t.id}i(hv,"g");typeof performance=="object"&&typeof performance.now=="function"?(Db=performance,tr.unstable_now=function(){return Db.now()}):(o1=Date,Ib=o1.now(),tr.unstable_now=function(){return o1.now()-Ib});var Db,o1,Ib,va=[],xu=[],QI=1,rs=null,ti=3,vv=!1,Zc=!1,Oh=!1,Hb=typeof setTimeout=="function"?setTimeout:null,zb=typeof clearTimeout=="function"?clearTimeout:null,Fb=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function u1(e){for(var t=Ps(xu);t!==null;){if(t.callback===null)gv(xu);else if(t.startTime<=e)gv(xu),t.sortIndex=t.expirationTime,l1(va,t);else break;t=Ps(xu)}}i(u1,"G");function c1(e){if(Oh=!1,u1(e),!Zc)if(Ps(va)!==null)Zc=!0,d1(f1);else{var t=Ps(xu);t!==null&&p1(c1,t.startTime-e)}}i(c1,"H");function f1(e,t){Zc=!1,Oh&&(Oh=!1,zb(Rh),Rh=-1),vv=!0;var n=ti;try{for(u1(t),rs=Ps(va);rs!==null&&(!(rs.expirationTime>t)||e&&!$b());){var s=rs.callback;if(typeof s=="function"){rs.callback=null,ti=rs.priorityLevel;var l=s(rs.expirationTime<=t);t=tr.unstable_now(),typeof l=="function"?rs.callback=l:rs===Ps(va)&&gv(va),u1(t)}else gv(va);rs=Ps(va)}if(rs!==null)var h=!0;else{var d=Ps(xu);d!==null&&p1(c1,d.startTime-t),h=!1}return h}finally{rs=null,ti=n,vv=!1}}i(f1,"J");var yv=!1,mv=null,Rh=-1,Ub=5,Wb=-1;function $b(){return!(tr.unstable_now()-Wbe||125s?(e.sortIndex=n,l1(xu,e),Ps(va)===null&&e===Ps(xu)&&(Oh?(zb(Rh),Rh=-1):Oh=!0,p1(c1,n-s))):(e.sortIndex=l,l1(va,e),Zc||vv||(Zc=!0,d1(f1))),e};tr.unstable_shouldYield=$b;tr.unstable_wrapCallback=function(e){var t=ti;return function(){var n=ti;ti=t;try{return e.apply(this,arguments)}finally{ti=n}}}});var jb=rt((RW,qb)=>{"use strict";qb.exports=Vb()});var XN=rt(Lo=>{"use strict";var JI=Te(),Ao=jb();function ge(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),I1=Object.prototype.hasOwnProperty,ZI=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Kb={},Gb={};function eF(e){return I1.call(Gb,e)?!0:I1.call(Kb,e)?!1:ZI.test(e)?Gb[e]=!0:(Kb[e]=!0,!1)}i(eF,"oa");function tF(e,t,n,s){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return s?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}i(tF,"pa");function rF(e,t,n,s){if(t===null||typeof t>"u"||tF(e,t,n,s))return!0;if(s)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}i(rF,"qa");function Ti(e,t,n,s,l,h,d){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=s,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=h,this.removeEmptyString=d}i(Ti,"v");var jn={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){jn[e]=new Ti(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];jn[t]=new Ti(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){jn[e]=new Ti(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){jn[e]=new Ti(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){jn[e]=new Ti(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){jn[e]=new Ti(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){jn[e]=new Ti(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){jn[e]=new Ti(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){jn[e]=new Ti(e,5,!1,e.toLowerCase(),null,!1,!1)});var NS=/[\-:]([a-z])/g;function AS(e){return e[1].toUpperCase()}i(AS,"sa");"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(NS,AS);jn[t]=new Ti(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(NS,AS);jn[t]=new Ti(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(NS,AS);jn[t]=new Ti(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){jn[e]=new Ti(e,1,!1,e.toLowerCase(),null,!1,!1)});jn.xlinkHref=new Ti("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){jn[e]=new Ti(e,1,!1,e.toLowerCase(),null,!0,!0)});function PS(e,t,n,s){var l=jn.hasOwnProperty(t)?jn[t]:null;(l!==null?l.type!==0:s||!(2v||l[d]!==h[v]){var S=` +`+l[d].replace(" at new "," at ");return e.displayName&&S.includes("")&&(S=S.replace("",e.displayName)),S}while(1<=d&&0<=v);break}}}finally{m1=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?$h(e):""}i(g1,"Oa");function nF(e){switch(e.tag){case 5:return $h(e.type);case 16:return $h("Lazy");case 13:return $h("Suspense");case 19:return $h("SuspenseList");case 0:case 2:case 15:return e=g1(e.type,!1),e;case 11:return e=g1(e.type.render,!1),e;case 1:return e=g1(e.type,!0),e;default:return""}}i(nF,"Pa");function z1(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Rd:return"Fragment";case Od:return"Portal";case F1:return"Profiler";case LS:return"StrictMode";case B1:return"Suspense";case H1:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case tk:return(e.displayName||"Context")+".Consumer";case ek:return(e._context.displayName||"Context")+".Provider";case MS:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case OS:return t=e.displayName||null,t!==null?t:z1(e.type)||"Memo";case _u:t=e._payload,e=e._init;try{return z1(e(t))}catch{}}return null}i(z1,"Qa");function iF(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return z1(t);case 8:return t===LS?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}i(iF,"Ra");function Fu(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}i(Fu,"Sa");function nk(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}i(nk,"Ta");function oF(e){var t=nk(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),s=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,h=n.set;return Object.defineProperty(e,t,{configurable:!0,get:i(function(){return l.call(this)},"get"),set:i(function(d){s=""+d,h.call(this,d)},"set")}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:i(function(){return s},"getValue"),setValue:i(function(d){s=""+d},"setValue"),stopTracking:i(function(){e._valueTracker=null,delete e[t]},"stopTracking")}}}i(oF,"Ua");function Sv(e){e._valueTracker||(e._valueTracker=oF(e))}i(Sv,"Va");function ik(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),s="";return e&&(s=nk(e)?e.checked?"true":"false":e.value),e=s,e!==n?(t.setValue(e),!0):!1}i(ik,"Wa");function Gv(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}i(Gv,"Xa");function U1(e,t){var n=t.checked;return Tr({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}i(U1,"Ya");function Xb(e,t){var n=t.defaultValue==null?"":t.defaultValue,s=t.checked!=null?t.checked:t.defaultChecked;n=Fu(t.value!=null?t.value:n),e._wrapperState={initialChecked:s,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}i(Xb,"Za");function ok(e,t){t=t.checked,t!=null&&PS(e,"checked",t,!1)}i(ok,"ab");function W1(e,t){ok(e,t);var n=Fu(t.value),s=t.type;if(n!=null)s==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(s==="submit"||s==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?$1(e,t.type,n):t.hasOwnProperty("defaultValue")&&$1(e,t.type,Fu(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}i(W1,"bb");function Qb(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var s=t.type;if(!(s!=="submit"&&s!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}i(Qb,"db");function $1(e,t,n){(t!=="number"||Gv(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}i($1,"cb");var Vh=Array.isArray;function qd(e,t,n,s){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=xv.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function nm(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}i(nm,"ob");var Kh={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},sF=["Webkit","ms","Moz","O"];Object.keys(Kh).forEach(function(e){sF.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Kh[t]=Kh[e]})});function uk(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Kh.hasOwnProperty(e)&&Kh[e]?(""+t).trim():t+"px"}i(uk,"rb");function ck(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var s=n.indexOf("--")===0,l=uk(n,t[n],s);n==="float"&&(n="cssFloat"),s?e.setProperty(n,l):e[n]=l}}i(ck,"sb");var aF=Tr({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function j1(e,t){if(t){if(aF[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(ge(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(ge(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(ge(61))}if(t.style!=null&&typeof t.style!="object")throw Error(ge(62))}}i(j1,"ub");function K1(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}i(K1,"vb");var G1=null;function RS(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}i(RS,"xb");var Y1=null,jd=null,Kd=null;function eT(e){if(e=xm(e)){if(typeof Y1!="function")throw Error(ge(280));var t=e.stateNode;t&&(t=Cy(t),Y1(e.stateNode,e.type,t))}}i(eT,"Bb");function fk(e){jd?Kd?Kd.push(e):Kd=[e]:jd=e}i(fk,"Eb");function dk(){if(jd){var e=jd,t=Kd;if(Kd=jd=null,eT(e),t)for(e=0;e>>=0,e===0?32:31-(yF(e)/wF|0)|0}i(SF,"nc");var Cv=64,_v=4194304;function qh(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}i(qh,"tc");function Jv(e,t){var n=e.pendingLanes;if(n===0)return 0;var s=0,l=e.suspendedLanes,h=e.pingedLanes,d=n&268435455;if(d!==0){var v=d&~l;v!==0?s=qh(v):(h&=d,h!==0&&(s=qh(h)))}else d=n&~l,d!==0?s=qh(d):h!==0&&(s=qh(h));if(s===0)return 0;if(t!==0&&t!==s&&!(t&l)&&(l=s&-s,h=t&-t,l>=h||l===16&&(h&4194240)!==0))return t;if(s&4&&(s|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=s;0n;n++)t.push(e);return t}i(y1,"zc");function wm(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ds(t),e[t]=n}i(wm,"Ac");function _F(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var s=e.eventTimes;for(e=e.expirationTimes;0=Yh),uT=" ",cT=!1;function Mk(e,t){switch(e){case"keyup":return QF.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}i(Mk,"ge");function Ok(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}i(Ok,"he");var Dd=!1;function ZF(e,t){switch(e){case"compositionend":return Ok(t);case"keypress":return t.which!==32?null:(cT=!0,uT);case"textInput":return e=t.data,e===uT&&cT?null:e;default:return null}}i(ZF,"je");function e3(e,t){if(Dd)return e==="compositionend"||!WS&&Mk(e,t)?(e=Pk(),Hv=HS=ku=null,Dd=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=s}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=pT(n)}}i(hT,"Ke");function Fk(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Fk(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}i(Fk,"Le");function Bk(){for(var e=window,t=Gv();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Gv(e.document)}return t}i(Bk,"Me");function $S(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}i($S,"Ne");function u3(e){var t=Bk(),n=e.focusedElem,s=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Fk(n.ownerDocument.documentElement,n)){if(s!==null&&$S(n)){if(t=s.start,e=s.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,h=Math.min(s.start,l);s=s.end===void 0?h:Math.min(s.end,l),!e.extend&&h>s&&(l=s,s=h,h=l),l=hT(n,h);var d=hT(n,s);l&&d&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==d.node||e.focusOffset!==d.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),h>s?(e.addRange(t),e.extend(d.node,d.offset)):(t.setEnd(d.node,d.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Id=null,tS=null,Qh=null,rS=!1;function mT(e,t,n){var s=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;rS||Id==null||Id!==Gv(s)||(s=Id,"selectionStart"in s&&$S(s)?s={start:s.selectionStart,end:s.selectionEnd}:(s=(s.ownerDocument&&s.ownerDocument.defaultView||window).getSelection(),s={anchorNode:s.anchorNode,anchorOffset:s.anchorOffset,focusNode:s.focusNode,focusOffset:s.focusOffset}),Qh&&um(Qh,s)||(Qh=s,s=ty(tS,"onSelect"),0Hd||(e.current=lS[Hd],lS[Hd]=null,Hd--)}i(cr,"E");function rr(e,t){Hd++,lS[Hd]=e.current,e.current=t}i(rr,"G");var Bu={},oi=zu(Bu),Ki=zu(!1),lf=Bu;function Jd(e,t){var n=e.type.contextTypes;if(!n)return Bu;var s=e.stateNode;if(s&&s.__reactInternalMemoizedUnmaskedChildContext===t)return s.__reactInternalMemoizedMaskedChildContext;var l={},h;for(h in n)l[h]=t[h];return s&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}i(Jd,"Yf");function Gi(e){return e=e.childContextTypes,e!=null}i(Gi,"Zf");function ny(){cr(Ki),cr(oi)}i(ny,"$f");function ET(e,t,n){if(oi.current!==Bu)throw Error(ge(168));rr(oi,t),rr(Ki,n)}i(ET,"ag");function Kk(e,t,n){var s=e.stateNode;if(t=t.childContextTypes,typeof s.getChildContext!="function")return n;s=s.getChildContext();for(var l in s)if(!(l in t))throw Error(ge(108,iF(e)||"Unknown",l));return Tr({},n,s)}i(Kk,"bg");function iy(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Bu,lf=oi.current,rr(oi,e),rr(Ki,Ki.current),!0}i(iy,"cg");function bT(e,t,n){var s=e.stateNode;if(!s)throw Error(ge(169));n?(e=Kk(e,t,lf),s.__reactInternalMemoizedMergedChildContext=e,cr(Ki),cr(oi),rr(oi,e)):cr(Ki),rr(Ki,n)}i(bT,"dg");var al=null,_y=!1,k1=!1;function Gk(e){al===null?al=[e]:al.push(e)}i(Gk,"hg");function w3(e){_y=!0,Gk(e)}i(w3,"ig");function Uu(){if(!k1&&al!==null){k1=!0;var e=0,t=Vt;try{var n=al;for(Vt=1;e>=d,l-=d,ll=1<<32-Ds(t)+l|n<he?(Re=oe,oe=null):Re=oe.sibling;var Ee=I(D,oe,B[he],j);if(Ee===null){oe===null&&(oe=Re);break}e&&oe&&Ee.alternate===null&&t(D,oe),L=h(Ee,L,he),Z===null?re=Ee:Z.sibling=Ee,Z=Ee,oe=Re}if(he===B.length)return n(D,oe),hr&&ef(D,he),re;if(oe===null){for(;hehe?(Re=oe,oe=null):Re=oe.sibling;var Ye=I(D,oe,Ee.value,j);if(Ye===null){oe===null&&(oe=Re);break}e&&oe&&Ye.alternate===null&&t(D,oe),L=h(Ye,L,he),Z===null?re=Ye:Z.sibling=Ye,Z=Ye,oe=Re}if(Ee.done)return n(D,oe),hr&&ef(D,he),re;if(oe===null){for(;!Ee.done;he++,Ee=B.next())Ee=R(D,Ee.value,j),Ee!==null&&(L=h(Ee,L,he),Z===null?re=Ee:Z.sibling=Ee,Z=Ee);return hr&&ef(D,he),re}for(oe=s(D,oe);!Ee.done;he++,Ee=B.next())Ee=z(oe,D,he,Ee.value,j),Ee!==null&&(e&&Ee.alternate!==null&&oe.delete(Ee.key===null?he:Ee.key),L=h(Ee,L,he),Z===null?re=Ee:Z.sibling=Ee,Z=Ee);return e&&oe.forEach(function(tt){return t(D,tt)}),hr&&ef(D,he),re}i(Q,"t");function ne(D,L,B,j){if(typeof B=="object"&&B!==null&&B.type===Rd&&B.key===null&&(B=B.props.children),typeof B=="object"&&B!==null){switch(B.$$typeof){case wv:e:{for(var re=B.key,Z=L;Z!==null;){if(Z.key===re){if(re=B.type,re===Rd){if(Z.tag===7){n(D,Z.sibling),L=l(Z,B.props.children),L.return=D,D=L;break e}}else if(Z.elementType===re||typeof re=="object"&&re!==null&&re.$$typeof===_u&&NT(re)===Z.type){n(D,Z.sibling),L=l(Z,B.props),L.ref=Hh(D,Z,B),L.return=D,D=L;break e}n(D,Z);break}else t(D,Z);Z=Z.sibling}B.type===Rd?(L=af(B.props.children,D.mode,j,B.key),L.return=D,D=L):(j=Kv(B.type,B.key,B.props,null,D.mode,j),j.ref=Hh(D,L,B),j.return=D,D=j)}return d(D);case Od:e:{for(Z=B.key;L!==null;){if(L.key===Z)if(L.tag===4&&L.stateNode.containerInfo===B.containerInfo&&L.stateNode.implementation===B.implementation){n(D,L.sibling),L=l(L,B.children||[]),L.return=D,D=L;break e}else{n(D,L);break}else t(D,L);L=L.sibling}L=D1(B,D.mode,j),L.return=D,D=L}return d(D);case _u:return Z=B._init,ne(D,L,Z(B._payload),j)}if(Vh(B))return q(D,L,B,j);if(Dh(B))return Q(D,L,B,j);Rv(D,B)}return typeof B=="string"&&B!==""||typeof B=="number"?(B=""+B,L!==null&&L.tag===6?(n(D,L.sibling),L=l(L,B),L.return=D,D=L):(n(D,L),L=R1(B,D.mode,j),L.return=D,D=L),d(D)):n(D,L)}return i(ne,"J"),ne}i(Jk,"Og");var ep=Jk(!0),Zk=Jk(!1),ay=zu(null),ly=null,Wd=null,KS=null;function GS(){KS=Wd=ly=null}i(GS,"$g");function YS(e){var t=ay.current;cr(ay),e._currentValue=t}i(YS,"ah");function fS(e,t,n){for(;e!==null;){var s=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,s!==null&&(s.childLanes|=t)):s!==null&&(s.childLanes&t)!==t&&(s.childLanes|=t),e===n)break;e=e.return}}i(fS,"bh");function Yd(e,t){ly=e,KS=Wd=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(ji=!0),e.firstContext=null)}i(Yd,"ch");function as(e){var t=e._currentValue;if(KS!==e)if(e={context:e,memoizedValue:t,next:null},Wd===null){if(ly===null)throw Error(ge(308));Wd=e,ly.dependencies={lanes:0,firstContext:e}}else Wd=Wd.next=e;return t}i(as,"eh");var nf=null;function XS(e){nf===null?nf=[e]:nf.push(e)}i(XS,"gh");function eN(e,t,n,s){var l=t.interleaved;return l===null?(n.next=n,XS(t)):(n.next=l.next,l.next=n),t.interleaved=n,pl(e,s)}i(eN,"hh");function pl(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}i(pl,"ih");var Eu=!1;function QS(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}i(QS,"kh");function tN(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}i(tN,"lh");function cl(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}i(cl,"mh");function Ou(e,t,n){var s=e.updateQueue;if(s===null)return null;if(s=s.shared,Nt&2){var l=s.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),s.pending=t,pl(e,n)}return l=s.interleaved,l===null?(t.next=t,XS(s)):(t.next=l.next,l.next=t),s.interleaved=t,pl(e,n)}i(Ou,"nh");function Uv(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var s=t.lanes;s&=e.pendingLanes,n|=s,t.lanes=n,IS(e,n)}}i(Uv,"oh");function AT(e,t){var n=e.updateQueue,s=e.alternate;if(s!==null&&(s=s.updateQueue,n===s)){var l=null,h=null;if(n=n.firstBaseUpdate,n!==null){do{var d={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};h===null?l=h=d:h=h.next=d,n=n.next}while(n!==null);h===null?l=h=t:h=h.next=t}else l=h=t;n={baseState:s.baseState,firstBaseUpdate:l,lastBaseUpdate:h,shared:s.shared,effects:s.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}i(AT,"ph");function uy(e,t,n,s){var l=e.updateQueue;Eu=!1;var h=l.firstBaseUpdate,d=l.lastBaseUpdate,v=l.shared.pending;if(v!==null){l.shared.pending=null;var S=v,b=S.next;S.next=null,d===null?h=b:d.next=b,d=S;var k=e.alternate;k!==null&&(k=k.updateQueue,v=k.lastBaseUpdate,v!==d&&(v===null?k.firstBaseUpdate=b:v.next=b,k.lastBaseUpdate=S))}if(h!==null){var R=l.baseState;d=0,k=b=S=null,v=h;do{var I=v.lane,z=v.eventTime;if((s&I)===I){k!==null&&(k=k.next={eventTime:z,lane:0,tag:v.tag,payload:v.payload,callback:v.callback,next:null});e:{var q=e,Q=v;switch(I=t,z=n,Q.tag){case 1:if(q=Q.payload,typeof q=="function"){R=q.call(z,R,I);break e}R=q;break e;case 3:q.flags=q.flags&-65537|128;case 0:if(q=Q.payload,I=typeof q=="function"?q.call(z,R,I):q,I==null)break e;R=Tr({},R,I);break e;case 2:Eu=!0}}v.callback!==null&&v.lane!==0&&(e.flags|=64,I=l.effects,I===null?l.effects=[v]:I.push(v))}else z={eventTime:z,lane:I,tag:v.tag,payload:v.payload,callback:v.callback,next:null},k===null?(b=k=z,S=R):k=k.next=z,d|=I;if(v=v.next,v===null){if(v=l.shared.pending,v===null)break;I=v,v=I.next,I.next=null,l.lastBaseUpdate=I,l.shared.pending=null}}while(!0);if(k===null&&(S=R),l.baseState=S,l.firstBaseUpdate=b,l.lastBaseUpdate=k,t=l.shared.interleaved,t!==null){l=t;do d|=l.lane,l=l.next;while(l!==t)}else h===null&&(l.shared.lanes=0);ff|=d,e.lanes=d,e.memoizedState=R}}i(uy,"qh");function PT(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var s=A1.transition;A1.transition={};try{e(!1),t()}finally{Vt=n,A1.transition=s}}i(C3,"vi");function yN(){return ls().memoizedState}i(yN,"wi");function _3(e,t,n){var s=Du(e);if(n={lane:s,action:n,hasEagerState:!1,eagerState:null,next:null},wN(e))SN(t,n);else if(n=eN(e,t,n,s),n!==null){var l=bi();Is(n,e,s,l),xN(n,t,s)}}i(_3,"xi");function E3(e,t,n){var s=Du(e),l={lane:s,action:n,hasEagerState:!1,eagerState:null,next:null};if(wN(e))SN(t,l);else{var h=e.alternate;if(e.lanes===0&&(h===null||h.lanes===0)&&(h=t.lastRenderedReducer,h!==null))try{var d=t.lastRenderedState,v=h(d,n);if(l.hasEagerState=!0,l.eagerState=v,Fs(v,d)){var S=t.interleaved;S===null?(l.next=l,XS(t)):(l.next=S.next,S.next=l),t.interleaved=l;return}}catch{}finally{}n=eN(e,t,l,s),n!==null&&(l=bi(),Is(n,e,s,l),xN(n,t,s))}}i(E3,"ii");function wN(e){var t=e.alternate;return e===br||t!==null&&t===br}i(wN,"zi");function SN(e,t){Jh=fy=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}i(SN,"Ai");function xN(e,t,n){if(n&4194240){var s=t.lanes;s&=e.pendingLanes,n|=s,t.lanes=n,IS(e,n)}}i(xN,"Bi");var dy={readContext:as,useCallback:ri,useContext:ri,useEffect:ri,useImperativeHandle:ri,useInsertionEffect:ri,useLayoutEffect:ri,useMemo:ri,useReducer:ri,useRef:ri,useState:ri,useDebugValue:ri,useDeferredValue:ri,useTransition:ri,useMutableSource:ri,useSyncExternalStore:ri,useId:ri,unstable_isNewReconciler:!1},b3={readContext:as,useCallback:i(function(e,t){return wa().memoizedState=[e,t===void 0?null:t],e},"useCallback"),useContext:as,useEffect:MT,useImperativeHandle:i(function(e,t,n){return n=n!=null?n.concat([e]):null,$v(4194308,4,pN.bind(null,t,e),n)},"useImperativeHandle"),useLayoutEffect:i(function(e,t){return $v(4194308,4,e,t)},"useLayoutEffect"),useInsertionEffect:i(function(e,t){return $v(4,2,e,t)},"useInsertionEffect"),useMemo:i(function(e,t){var n=wa();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},"useMemo"),useReducer:i(function(e,t,n){var s=wa();return t=n!==void 0?n(t):t,s.memoizedState=s.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},s.queue=e,e=e.dispatch=_3.bind(null,br,e),[s.memoizedState,e]},"useReducer"),useRef:i(function(e){var t=wa();return e={current:e},t.memoizedState=e},"useRef"),useState:LT,useDebugValue:ox,useDeferredValue:i(function(e){return wa().memoizedState=e},"useDeferredValue"),useTransition:i(function(){var e=LT(!1),t=e[0];return e=C3.bind(null,e[1]),wa().memoizedState=e,[t,e]},"useTransition"),useMutableSource:i(function(){},"useMutableSource"),useSyncExternalStore:i(function(e,t,n){var s=br,l=wa();if(hr){if(n===void 0)throw Error(ge(407));n=n()}else{if(n=t(),Mn===null)throw Error(ge(349));cf&30||oN(s,t,n)}l.memoizedState=n;var h={value:n,getSnapshot:t};return l.queue=h,MT(aN.bind(null,s,h,e),[e]),s.flags|=2048,vm(9,sN.bind(null,s,h,n,t),void 0,null),n},"useSyncExternalStore"),useId:i(function(){var e=wa(),t=Mn.identifierPrefix;if(hr){var n=ul,s=ll;n=(s&~(1<<32-Ds(s)-1)).toString(32)+n,t=":"+t+"R"+n,n=mm++,0d&&(d=c),n&=~h}if(n=d,n=Qn()-n,n=(120>n?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*oI(n/1960))-n,10 component higher in the tree to provide a loading indicator or placeholder to display.`)}Fn!==5&&(Fn=2),C=gx(C,v),B=c;do{switch(B.tag){case 3:h=C,B.flags|=4096,t&=-t,B.lanes|=t;var se=OT(B,h,t);G_(B,se);break e;case 1:h=C;var ne=B.type,pe=B.stateNode;if((B.flags&64)==0&&(typeof ne.getDerivedStateFromError=="function"||pe!==null&&typeof pe.componentDidCatch=="function"&&(Ks===null||!Ks.has(pe)))){B.flags|=4096,t&=-t,B.lanes|=t;var me=MT(B,h,t);G_(B,me);break e}}B=B.return}while(B!==null)}KT(n)}catch(xe){t=xe,sn===n&&n!==null&&(sn=n=n.return);continue}break}while(1)}o(jT,"Sj");function qT(){var e=Bv.current;return Bv.current=Iv,e===null?Iv:e}o(qT,"Pj");function jh(e,t){var n=Ze;Ze|=16;var l=qT();yi===e&&Jn===t||Ep(e,t);do try{lI();break}catch(d){jT(e,d)}while(1);if(X1(),Ze=n,Bv.current=l,sn!==null)throw Error(we(261));return yi=null,Jn=0,Fn}o(jh,"Tj");function lI(){for(;sn!==null;)VT(sn)}o(lI,"ak");function aI(){for(;sn!==null&&!$R();)VT(sn)}o(aI,"Rj");function VT(e){var t=XT(e.alternate,e,Tf);e.memoizedProps=e.pendingProps,t===null?KT(e):sn=t,Sx.current=null}o(VT,"bk");function KT(e){var t=e;do{var n=t.alternate;if(e=t.return,(t.flags&2048)==0){if(n=ZR(n,t,Tf),n!==null){sn=n;return}if(n=t,n.tag!==24&&n.tag!==23||n.memoizedState===null||(Tf&1073741824)!=0||(n.mode&4)==0){for(var l=0,d=n.child;d!==null;)l|=d.lanes|d.childLanes,d=d.sibling;n.childLanes=l}e!==null&&(e.flags&2048)==0&&(e.firstEffect===null&&(e.firstEffect=t.firstEffect),t.lastEffect!==null&&(e.lastEffect!==null&&(e.lastEffect.nextEffect=t.firstEffect),e.lastEffect=t.lastEffect),1c&&(v=c,c=se,se=v),v=v_(I,se),h=v_(I,c),v&&h&&(K.rangeCount!==1||K.anchorNode!==v.node||K.anchorOffset!==v.offset||K.focusNode!==h.node||K.focusOffset!==h.offset)&&(G=G.createRange(),G.setStart(v.node,v.offset),K.removeAllRanges(),se>c?(K.addRange(G),K.extend(h.node,h.offset)):(G.setEnd(h.node,h.offset),K.addRange(G)))))),G=[],K=I;K=K.parentNode;)K.nodeType===1&&G.push({element:K,left:K.scrollLeft,top:K.scrollTop});for(typeof I.focus=="function"&&I.focus(),I=0;IQn()-_x?Ep(e,0):bx|=n),ko(e,t)}o(dI,"Yj");function hI(e,t){var n=e.stateNode;n!==null&&n.delete(t),t=0,t===0&&(t=e.mode,(t&2)==0?t=1:(t&4)==0?t=mp()===99?1:2:(Dl===0&&(Dl=xp),t=op(62914560&~Dl),t===0&&(t=4194304))),n=Ji(),e=jv(e,t),e!==null&&(nv(e,t,n),ko(e,n))}o(hI,"lj");var XT;XT=o(function(e,t,n){var l=t.lanes;if(e!==null)if(e.memoizedProps!==t.pendingProps||Ri.current)ls=!0;else if((n&l)!=0)ls=(e.flags&16384)!=0;else{switch(ls=!1,t.tag){case 3:ST(t),nx();break;case 5:rT(t);break;case 1:Ii(t.type)&&wv(t);break;case 4:ex(t,t.stateNode.containerInfo);break;case 10:l=t.memoizedProps.value;var d=t.type._context;_r(Cv,d._currentValue),d._currentValue=l;break;case 13:if(t.memoizedState!==null)return(n&t.child.childLanes)!=0?CT(e,t,n):(_r(Tr,Tr.current&1),t=Ml(e,t,n),t!==null?t.sibling:null);_r(Tr,Tr.current&1);break;case 19:if(l=(n&t.childLanes)!=0,(e.flags&64)!=0){if(l)return kT(e,t,n);t.flags|=64}if(d=t.memoizedState,d!==null&&(d.rendering=null,d.tail=null,d.lastEffect=null),_r(Tr,Tr.current),l)break;return null;case 23:case 24:return t.lanes=0,cx(e,t,n)}return Ml(e,t,n)}else ls=!1;switch(t.lanes=0,t.tag){case 2:if(l=t.type,e!==null&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,d=hp(t,Xn.current),vp(t,n),d=sx(null,t,l,e,d,n),t.flags|=1,typeof d=="object"&&d!==null&&typeof d.render=="function"&&d.$$typeof===void 0){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,Ii(l)){var h=!0;wv(t)}else h=!1;t.memoizedState=d.state!==null&&d.state!==void 0?d.state:null,Z1(t);var c=l.getDerivedStateFromProps;typeof c=="function"&&_v(t,l,c,e),d.updater=Tv,t.stateNode=d,d._reactInternals=t,J1(t,l,e,n),t=dx(null,t,l,!0,h,n)}else t.tag=0,Bi(null,t,d,n),t=t.child;return t;case 16:d=t.elementType;e:{switch(e!==null&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,h=d._init,d=h(d._payload),t.type=d,h=t.tag=gI(d),e=ss(d,e),h){case 0:t=px(null,t,d,e,n);break e;case 1:t=xT(null,t,d,e,n);break e;case 11:t=gT(null,t,d,e,n);break e;case 14:t=vT(null,t,d,ss(d.type,e),l,n);break e}throw Error(we(306,d,""))}return t;case 0:return l=t.type,d=t.pendingProps,d=t.elementType===l?d:ss(l,d),px(e,t,l,d,n);case 1:return l=t.type,d=t.pendingProps,d=t.elementType===l?d:ss(l,d),xT(e,t,l,d,n);case 3:if(ST(t),l=t.updateQueue,e===null||l===null)throw Error(we(282));if(l=t.pendingProps,d=t.memoizedState,d=d!==null?d.element:null,K_(e,t),kh(t,l,null,n),l=t.memoizedState.element,l===d)nx(),t=Ml(e,t,n);else{if(d=t.stateNode,(h=d.hydrate)&&(Qa=fp(t.stateNode.containerInfo.firstChild),Ol=t,h=qs=!0),h){if(e=d.mutableSourceEagerHydrationData,e!=null)for(d=0;d{"use strict";function ek(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__=="undefined"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(ek)}catch(e){console.error(e)}}o(ek,"checkDCE");ek(),tk.exports=JT()});var nk=Ue((yH,rk)=>{"use strict";var bI="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";rk.exports=bI});var lk=Ue((wH,sk)=>{"use strict";var EI=nk();function ik(){}o(ik,"emptyFunction");function ok(){}o(ok,"emptyFunctionWithReset");ok.resetWarningCache=ik;sk.exports=function(){function e(l,d,h,c,v,C){if(C!==EI){var k=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw k.name="Invariant Violation",k}}o(e,"shim"),e.isRequired=e;function t(){return e}o(t,"getShim");var n={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:ok,resetWarningCache:ik};return n.PropTypes=n,n}});var uk=Ue((CH,ak)=>{ak.exports=lk()();var xH,SH});var gk=Ue(Ht=>{"use strict";var kn=typeof Symbol=="function"&&Symbol.for,Ux=kn?Symbol.for("react.element"):60103,zx=kn?Symbol.for("react.portal"):60106,Xv=kn?Symbol.for("react.fragment"):60107,Qv=kn?Symbol.for("react.strict_mode"):60108,Zv=kn?Symbol.for("react.profiler"):60114,Jv=kn?Symbol.for("react.provider"):60109,e0=kn?Symbol.for("react.context"):60110,$x=kn?Symbol.for("react.async_mode"):60111,t0=kn?Symbol.for("react.concurrent_mode"):60111,r0=kn?Symbol.for("react.forward_ref"):60112,n0=kn?Symbol.for("react.suspense"):60113,NI=kn?Symbol.for("react.suspense_list"):60120,i0=kn?Symbol.for("react.memo"):60115,o0=kn?Symbol.for("react.lazy"):60116,LI=kn?Symbol.for("react.block"):60121,PI=kn?Symbol.for("react.fundamental"):60117,OI=kn?Symbol.for("react.responder"):60118,MI=kn?Symbol.for("react.scope"):60119;function eo(e){if(typeof e=="object"&&e!==null){var t=e.$$typeof;switch(t){case Ux:switch(e=e.type,e){case $x:case t0:case Xv:case Zv:case Qv:case n0:return e;default:switch(e=e&&e.$$typeof,e){case e0:case r0:case o0:case i0:case Jv:return e;default:return t}}case zx:return t}}}o(eo,"z");function mk(e){return eo(e)===t0}o(mk,"A");Ht.AsyncMode=$x;Ht.ConcurrentMode=t0;Ht.ContextConsumer=e0;Ht.ContextProvider=Jv;Ht.Element=Ux;Ht.ForwardRef=r0;Ht.Fragment=Xv;Ht.Lazy=o0;Ht.Memo=i0;Ht.Portal=zx;Ht.Profiler=Zv;Ht.StrictMode=Qv;Ht.Suspense=n0;Ht.isAsyncMode=function(e){return mk(e)||eo(e)===$x};Ht.isConcurrentMode=mk;Ht.isContextConsumer=function(e){return eo(e)===e0};Ht.isContextProvider=function(e){return eo(e)===Jv};Ht.isElement=function(e){return typeof e=="object"&&e!==null&&e.$$typeof===Ux};Ht.isForwardRef=function(e){return eo(e)===r0};Ht.isFragment=function(e){return eo(e)===Xv};Ht.isLazy=function(e){return eo(e)===o0};Ht.isMemo=function(e){return eo(e)===i0};Ht.isPortal=function(e){return eo(e)===zx};Ht.isProfiler=function(e){return eo(e)===Zv};Ht.isStrictMode=function(e){return eo(e)===Qv};Ht.isSuspense=function(e){return eo(e)===n0};Ht.isValidElementType=function(e){return typeof e=="string"||typeof e=="function"||e===Xv||e===t0||e===Zv||e===Qv||e===n0||e===NI||typeof e=="object"&&e!==null&&(e.$$typeof===o0||e.$$typeof===i0||e.$$typeof===Jv||e.$$typeof===e0||e.$$typeof===r0||e.$$typeof===PI||e.$$typeof===OI||e.$$typeof===MI||e.$$typeof===LI)};Ht.typeOf=eo});var yk=Ue((FH,vk)=>{"use strict";vk.exports=gk()});var _k=Ue((BH,Ek)=>{"use strict";var jx=yk(),AI={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},DI={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},RI={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},wk={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},qx={};qx[jx.ForwardRef]=RI;qx[jx.Memo]=wk;function xk(e){return jx.isMemo(e)?wk:qx[e.$$typeof]||AI}o(xk,"getStatics");var II=Object.defineProperty,FI=Object.getOwnPropertyNames,Sk=Object.getOwnPropertySymbols,BI=Object.getOwnPropertyDescriptor,HI=Object.getPrototypeOf,Ck=Object.prototype;function bk(e,t,n){if(typeof t!="string"){if(Ck){var l=HI(t);l&&l!==Ck&&bk(e,l,n)}var d=FI(t);Sk&&(d=d.concat(Sk(t)));for(var h=xk(e),c=xk(t),v=0;v{"use strict";var Nn=typeof Symbol=="function"&&Symbol.for,Vx=Nn?Symbol.for("react.element"):60103,Kx=Nn?Symbol.for("react.portal"):60106,s0=Nn?Symbol.for("react.fragment"):60107,l0=Nn?Symbol.for("react.strict_mode"):60108,a0=Nn?Symbol.for("react.profiler"):60114,u0=Nn?Symbol.for("react.provider"):60109,f0=Nn?Symbol.for("react.context"):60110,Gx=Nn?Symbol.for("react.async_mode"):60111,c0=Nn?Symbol.for("react.concurrent_mode"):60111,p0=Nn?Symbol.for("react.forward_ref"):60112,d0=Nn?Symbol.for("react.suspense"):60113,WI=Nn?Symbol.for("react.suspense_list"):60120,h0=Nn?Symbol.for("react.memo"):60115,m0=Nn?Symbol.for("react.lazy"):60116,UI=Nn?Symbol.for("react.block"):60121,zI=Nn?Symbol.for("react.fundamental"):60117,$I=Nn?Symbol.for("react.responder"):60118,jI=Nn?Symbol.for("react.scope"):60119;function to(e){if(typeof e=="object"&&e!==null){var t=e.$$typeof;switch(t){case Vx:switch(e=e.type,e){case Gx:case c0:case s0:case a0:case l0:case d0:return e;default:switch(e=e&&e.$$typeof,e){case f0:case p0:case m0:case h0:case u0:return e;default:return t}}case Kx:return t}}}o(to,"z");function Tk(e){return to(e)===c0}o(Tk,"A");Wt.AsyncMode=Gx;Wt.ConcurrentMode=c0;Wt.ContextConsumer=f0;Wt.ContextProvider=u0;Wt.Element=Vx;Wt.ForwardRef=p0;Wt.Fragment=s0;Wt.Lazy=m0;Wt.Memo=h0;Wt.Portal=Kx;Wt.Profiler=a0;Wt.StrictMode=l0;Wt.Suspense=d0;Wt.isAsyncMode=function(e){return Tk(e)||to(e)===Gx};Wt.isConcurrentMode=Tk;Wt.isContextConsumer=function(e){return to(e)===f0};Wt.isContextProvider=function(e){return to(e)===u0};Wt.isElement=function(e){return typeof e=="object"&&e!==null&&e.$$typeof===Vx};Wt.isForwardRef=function(e){return to(e)===p0};Wt.isFragment=function(e){return to(e)===s0};Wt.isLazy=function(e){return to(e)===m0};Wt.isMemo=function(e){return to(e)===h0};Wt.isPortal=function(e){return to(e)===Kx};Wt.isProfiler=function(e){return to(e)===a0};Wt.isStrictMode=function(e){return to(e)===l0};Wt.isSuspense=function(e){return to(e)===d0};Wt.isValidElementType=function(e){return typeof e=="string"||typeof e=="function"||e===s0||e===c0||e===a0||e===l0||e===d0||e===WI||typeof e=="object"&&e!==null&&(e.$$typeof===m0||e.$$typeof===h0||e.$$typeof===u0||e.$$typeof===f0||e.$$typeof===p0||e.$$typeof===zI||e.$$typeof===$I||e.$$typeof===jI||e.$$typeof===UI)};Wt.typeOf=to});var Lk=Ue((WH,Nk)=>{"use strict";Nk.exports=kk()});var Qh=Ue((Np,Xh)=>{(function(){var e,t="4.17.21",n=200,l="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",d="Expected a function",h="Invalid `variable` option passed into `_.template`",c="__lodash_hash_undefined__",v=500,C="__lodash_placeholder__",k=1,O=2,j=4,B=1,X=2,J=1,Z=2,R=4,A=8,I=16,G=32,K=64,se=128,ne=256,pe=512,me=30,xe="...",Ve=800,tt=16,_e=1,St=2,We=3,Ke=1/0,Ge=9007199254740991,Xe=17976931348623157e292,nr=0/0,ct=4294967295,Hr=ct-1,Zt=ct>>>1,_t=[["ary",se],["bind",J],["bindKey",Z],["curry",A],["curryRight",I],["flip",pe],["partial",G],["partialRight",K],["rearg",ne]],Ct="[object Arguments]",ut="[object Array]",Lr="[object AsyncFunction]",zt="[object Boolean]",$t="[object Date]",ie="[object DOMException]",rt="[object Error]",Pr="[object Function]",Gt="[object GeneratorFunction]",Yt="[object Map]",Se="[object Number]",Or="[object Null]",fn="[object Object]",Un="[object Promise]",si="[object Proxy]",cn="[object RegExp]",Jt="[object Set]",gr="[object String]",pt="[object Symbol]",Ho="[object Undefined]",Cr="[object WeakMap]",Ui="[object WeakSet]",pn="[object ArrayBuffer]",zn="[object DataView]",Si="[object Float32Array]",Ci="[object Float64Array]",$n="[object Int8Array]",Mn="[object Int16Array]",Js="[object Int32Array]",H="[object Uint8Array]",ee="[object Uint8ClampedArray]",he="[object Uint16Array]",Te="[object Uint32Array]",ir=/\b__p \+= '';/g,Ul=/\b(__p \+=) '' \+/g,Ft=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Wr=/&(?:amp|lt|gt|quot|#39);/g,or=/[&<>"']/g,li=RegExp(Wr.source),ds=RegExp(or.source),lo=/<%-([\s\S]+?)%>/g,bi=/<%([\s\S]+?)%>/g,el=/<%=([\s\S]+?)%>/g,hs=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,dn=/^\w*$/,id=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,tl=/[\\^$.*+?()[\]{}|]/g,Qf=RegExp(tl.source),rl=/^\s+/,od=/\s/,Zf=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,wu=/\{\n\/\* \[wrapped with (.+)\] \*/,sd=/,? & /,zl=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,ms=/[()=,{}\[\]\/\s]/,ld=/\\(\\)?/g,Jf=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,nl=/\w*$/,xu=/^[-+]0x[0-9a-f]+$/i,Wo=/^0b[01]+$/i,ad=/^\[object .+?Constructor\]$/,Uo=/^0o[0-7]+$/i,$l=/^(?:0|[1-9]\d*)$/,ec=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,jt=/($^)/,Me=/['\n\r\u2028\u2029\\]/g,Ei="\\ud800-\\udfff",Su="\\u0300-\\u036f",ai="\\ufe20-\\ufe2f",vt="\\u20d0-\\u20ff",ao=Su+ai+vt,zo="\\u2700-\\u27bf",jl="a-z\\xdf-\\xf6\\xf8-\\xff",ue="\\xac\\xb1\\xd7\\xf7",ze="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",Cu="\\u2000-\\u206f",bu=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",gs="A-Z\\xc0-\\xd6\\xd8-\\xde",il="\\ufe0e\\ufe0f",Eu=ue+ze+Cu+bu,He="['\u2019]",ud="["+Ei+"]",ql="["+Eu+"]",uo="["+ao+"]",ui="\\d+",tc="["+zo+"]",_u="["+jl+"]",$o="[^"+Ei+Eu+ui+zo+jl+gs+"]",vs="\\ud83c[\\udffb-\\udfff]",Tu="(?:"+uo+"|"+vs+")",ol="[^"+Ei+"]",Vl="(?:\\ud83c[\\udde6-\\uddff]){2}",Kl="[\\ud800-\\udbff][\\udc00-\\udfff]",fo="["+gs+"]",Gl="\\u200d",Yl="(?:"+_u+"|"+$o+")",rc="(?:"+fo+"|"+$o+")",Xl="(?:"+He+"(?:d|ll|m|re|s|t|ve))?",_i="(?:"+He+"(?:D|LL|M|RE|S|T|VE))?",nc=Tu+"?",Ql="["+il+"]?",co="(?:"+Gl+"(?:"+[ol,Vl,Kl].join("|")+")"+Ql+nc+")*",ys="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",ic="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",oc=Ql+nc+co,fd="(?:"+[tc,Vl,Kl].join("|")+")"+oc,cd="(?:"+[ol+uo+"?",uo,Vl,Kl,ud].join("|")+")",ku=RegExp(He,"g"),sc=RegExp(uo,"g"),Nu=RegExp(vs+"(?="+vs+")|"+cd+oc,"g"),lc=RegExp([fo+"?"+_u+"+"+Xl+"(?="+[ql,fo,"$"].join("|")+")",rc+"+"+_i+"(?="+[ql,fo+Yl,"$"].join("|")+")",fo+"?"+Yl+"+"+Xl,fo+"+"+_i,ic,ys,ui,fd].join("|"),"g"),ac=RegExp("["+Gl+Ei+ao+il+"]"),Zl=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Jl=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Lu=-1,Ot={};Ot[Si]=Ot[Ci]=Ot[$n]=Ot[Mn]=Ot[Js]=Ot[H]=Ot[ee]=Ot[he]=Ot[Te]=!0,Ot[Ct]=Ot[ut]=Ot[pn]=Ot[zt]=Ot[zn]=Ot[$t]=Ot[rt]=Ot[Pr]=Ot[Yt]=Ot[Se]=Ot[fn]=Ot[cn]=Ot[Jt]=Ot[gr]=Ot[Cr]=!1;var Nt={};Nt[Ct]=Nt[ut]=Nt[pn]=Nt[zn]=Nt[zt]=Nt[$t]=Nt[Si]=Nt[Ci]=Nt[$n]=Nt[Mn]=Nt[Js]=Nt[Yt]=Nt[Se]=Nt[fn]=Nt[cn]=Nt[Jt]=Nt[gr]=Nt[pt]=Nt[H]=Nt[ee]=Nt[he]=Nt[Te]=!0,Nt[rt]=Nt[Pr]=Nt[Cr]=!1;var P={\u00C0:"A",\u00C1:"A",\u00C2:"A",\u00C3:"A",\u00C4:"A",\u00C5:"A",\u00E0:"a",\u00E1:"a",\u00E2:"a",\u00E3:"a",\u00E4:"a",\u00E5:"a",\u00C7:"C",\u00E7:"c",\u00D0:"D",\u00F0:"d",\u00C8:"E",\u00C9:"E",\u00CA:"E",\u00CB:"E",\u00E8:"e",\u00E9:"e",\u00EA:"e",\u00EB:"e",\u00CC:"I",\u00CD:"I",\u00CE:"I",\u00CF:"I",\u00EC:"i",\u00ED:"i",\u00EE:"i",\u00EF:"i",\u00D1:"N",\u00F1:"n",\u00D2:"O",\u00D3:"O",\u00D4:"O",\u00D5:"O",\u00D6:"O",\u00D8:"O",\u00F2:"o",\u00F3:"o",\u00F4:"o",\u00F5:"o",\u00F6:"o",\u00F8:"o",\u00D9:"U",\u00DA:"U",\u00DB:"U",\u00DC:"U",\u00F9:"u",\u00FA:"u",\u00FB:"u",\u00FC:"u",\u00DD:"Y",\u00FD:"y",\u00FF:"y",\u00C6:"Ae",\u00E6:"ae",\u00DE:"Th",\u00FE:"th",\u00DF:"ss",\u0100:"A",\u0102:"A",\u0104:"A",\u0101:"a",\u0103:"a",\u0105:"a",\u0106:"C",\u0108:"C",\u010A:"C",\u010C:"C",\u0107:"c",\u0109:"c",\u010B:"c",\u010D:"c",\u010E:"D",\u0110:"D",\u010F:"d",\u0111:"d",\u0112:"E",\u0114:"E",\u0116:"E",\u0118:"E",\u011A:"E",\u0113:"e",\u0115:"e",\u0117:"e",\u0119:"e",\u011B:"e",\u011C:"G",\u011E:"G",\u0120:"G",\u0122:"G",\u011D:"g",\u011F:"g",\u0121:"g",\u0123:"g",\u0124:"H",\u0126:"H",\u0125:"h",\u0127:"h",\u0128:"I",\u012A:"I",\u012C:"I",\u012E:"I",\u0130:"I",\u0129:"i",\u012B:"i",\u012D:"i",\u012F:"i",\u0131:"i",\u0134:"J",\u0135:"j",\u0136:"K",\u0137:"k",\u0138:"k",\u0139:"L",\u013B:"L",\u013D:"L",\u013F:"L",\u0141:"L",\u013A:"l",\u013C:"l",\u013E:"l",\u0140:"l",\u0142:"l",\u0143:"N",\u0145:"N",\u0147:"N",\u014A:"N",\u0144:"n",\u0146:"n",\u0148:"n",\u014B:"n",\u014C:"O",\u014E:"O",\u0150:"O",\u014D:"o",\u014F:"o",\u0151:"o",\u0154:"R",\u0156:"R",\u0158:"R",\u0155:"r",\u0157:"r",\u0159:"r",\u015A:"S",\u015C:"S",\u015E:"S",\u0160:"S",\u015B:"s",\u015D:"s",\u015F:"s",\u0161:"s",\u0162:"T",\u0164:"T",\u0166:"T",\u0163:"t",\u0165:"t",\u0167:"t",\u0168:"U",\u016A:"U",\u016C:"U",\u016E:"U",\u0170:"U",\u0172:"U",\u0169:"u",\u016B:"u",\u016D:"u",\u016F:"u",\u0171:"u",\u0173:"u",\u0174:"W",\u0175:"w",\u0176:"Y",\u0177:"y",\u0178:"Y",\u0179:"Z",\u017B:"Z",\u017D:"Z",\u017A:"z",\u017C:"z",\u017E:"z",\u0132:"IJ",\u0133:"ij",\u0152:"Oe",\u0153:"oe",\u0149:"'n",\u017F:"s"},Re={"&":"&","<":"<",">":">",'"':""","'":"'"},sl={"&":"&","<":"<",">":">",""":'"',"'":"'"},vr={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Pu=parseFloat,ye=parseInt,jo=typeof global=="object"&&global&&global.Object===Object&&global,pd=typeof self=="object"&&self&&self.Object===Object&&self,qt=jo||pd||Function("return this")(),ea=typeof Np=="object"&&Np&&!Np.nodeType&&Np,hn=ea&&typeof Xh=="object"&&Xh&&!Xh.nodeType&&Xh,ws=hn&&hn.exports===ea,zi=ws&&jo.process,Ce=function(){try{var q=hn&&hn.require&&hn.require("util").types;return q||zi&&zi.binding&&zi.binding("util")}catch(re){}}(),ta=Ce&&Ce.isArrayBuffer,Ou=Ce&&Ce.isDate,nt=Ce&&Ce.isMap,uc=Ce&&Ce.isRegExp,fi=Ce&&Ce.isSet,ll=Ce&&Ce.isTypedArray;function Ur(q,re,Q){switch(Q.length){case 0:return q.call(re);case 1:return q.call(re,Q[0]);case 2:return q.call(re,Q[0],Q[1]);case 3:return q.call(re,Q[0],Q[1],Q[2])}return q.apply(re,Q)}o(Ur,"apply");function ra(q,re,Q,Pe){for(var Qe=-1,bt=q==null?0:q.length;++Qe-1}o(xs,"arrayIncludes");function qo(q,re,Q){for(var Pe=-1,Qe=q==null?0:q.length;++Pe-1;);return Q}o(qi,"charsStartIndex");function al(q,re){for(var Q=q.length;Q--&&Go(re,q[Q],0)>-1;);return Q}o(al,"charsEndIndex");function cc(q,re){for(var Q=q.length,Pe=0;Q--;)q[Q]===re&&++Pe;return Pe}o(cc,"countHolders");var Wu=oa(P),gd=oa(Re);function Uu(q){return"\\"+vr[q]}o(Uu,"escapeStringChar");function la(q,re){return q==null?e:q[re]}o(la,"getValue");function qn(q){return ac.test(q)}o(qn,"hasUnicode");function Ti(q){return Zl.test(q)}o(Ti,"hasUnicodeWord");function pc(q){for(var re,Q=[];!(re=q.next()).done;)Q.push(re.value);return Q}o(pc,"iteratorToArray");function aa(q){var re=-1,Q=Array(q.size);return q.forEach(function(Pe,Qe){Q[++re]=[Qe,Pe]}),Q}o(aa,"mapToArray");function dc(q,re){return function(Q){return q(re(Q))}}o(dc,"overArg");function Vi(q,re){for(var Q=-1,Pe=q.length,Qe=0,bt=[];++Q-1}o(Ky,"listCacheHas");function yc(s,f){var m=this.__data__,x=gl(m,s);return x<0?(++this.size,m.push([s,f])):m[x][1]=f,this}o(yc,"listCacheSet"),vo.prototype.clear=Cd,vo.prototype.delete=jm,vo.prototype.get=Yu,vo.prototype.has=Ky,vo.prototype.set=yc;function xr(s){var f=-1,m=s==null?0:s.length;for(this.clear();++f=f?s:f)),s}o(vl,"baseClamp");function Dn(s,f,m,x,_,L){var F,z=f&k,Y=f&O,le=f&j;if(m&&(F=_?m(s,x,_,L):m(s)),F!==e)return F;if(!Sr(s))return s;var ae=ot(s);if(ae){if(F=u(s),!z)return qr(s,F)}else{var ce=xn(s),Le=ce==Pr||ce==Gt;if(Ra(s))return Hd(s,z);if(ce==fn||ce==Ct||Le&&!_){if(F=Y||Le?{}:a(s),!z)return Y?hg(s,Xy(F,s)):iw(s,kd(F,s))}else{if(!Nt[ce])return _?s:{};F=p(s,ce,z)}}L||(L=new Ni);var Fe=L.get(s);if(Fe)return Fe;L.set(s,F),bb(s)?s.forEach(function(je){F.add(Dn(je,f,m,je,s,L))}):Sb(s)&&s.forEach(function(je,ht){F.set(ht,Dn(je,f,m,ht,s,L))});var $e=le?Y?Hc:ff:Y?Ai:_n,ft=ae?e:$e(s);return jn(ft||s,function(je,ht){ft&&(ht=je,je=s[ht]),Qu(F,ht,Dn(je,f,m,ht,s,L))}),F}o(Dn,"baseClone");function Ym(s){var f=_n(s);return function(m){return Xm(m,s,f)}}o(Ym,"baseConforms");function Xm(s,f,m){var x=m.length;if(s==null)return!x;for(s=mt(s);x--;){var _=m[x],L=f[_],F=s[_];if(F===e&&!(_ in s)||!L(F))return!1}return!0}o(Xm,"baseConformsTo");function Qm(s,f,m){if(typeof s!="function")throw new Kn(d);return At(function(){s.apply(e,m)},f)}o(Qm,"baseDelay");function va(s,f,m,x){var _=-1,L=xs,F=!0,z=s.length,Y=[],le=f.length;if(!z)return Y;m&&(f=yt(f,zr(m))),x?(L=qo,F=!1):f.length>=n&&(L=mn,F=!1,f=new tn(f));e:for(;++__?0:_+m),x=x===e||x>_?_:lt(x),x<0&&(x+=_),x=m>x?0:_b(x);m0&&m(z)?f>1?rn(z,f-1,m,x,_):$i(_,z):x||(_[_.length]=z)}return _}o(rn,"baseFlatten");var bc=gg(),$r=gg(!0);function hi(s,f){return s&&bc(s,f,_n)}o(hi,"baseForOwn");function Ec(s,f){return s&&$r(s,f,_n)}o(Ec,"baseForOwnRight");function Ju(s,f){return Vt(f,function(m){return _l(s[m])})}o(Ju,"baseFunctions");function Ds(s,f){f=Gi(f,s);for(var m=0,x=f.length;s!=null&&mf}o(_c,"baseGt");function Zm(s,f){return s!=null&&et.call(s,f)}o(Zm,"baseHas");function Jm(s,f){return s!=null&&f in mt(s)}o(Jm,"baseHasIn");function ya(s,f,m){return s>=Zr(f,m)&&s=120&&ae.length>=120)?new tn(F&&ae):e}ae=s[0];var ce=-1,Le=z[0];e:for(;++ce<_&&le.length-1;)z!==s&&pa.call(z,Y,1),pa.call(s,Y,1);return s}o(Md,"basePullAll");function Ad(s,f){for(var m=s?f.length:0,x=m-1;m--;){var _=f[m];if(m==x||_!==L){var L=_;S(_)?pa.call(s,_,1):of(s,_)}}return s}o(Ad,"basePullAt");function Pc(s,f){return s+ha(Ns()*(f-s+1))}o(Pc,"baseRandom");function ag(s,f,m,x){for(var _=-1,L=sr(da((f-s)/(m||1)),0),F=Q(L);L--;)F[x?L:++_]=s,s+=m;return F}o(ag,"baseRange");function Dd(s,f){var m="";if(!s||f<1||f>Ge)return m;do f%2&&(m+=s),f=ha(f/2),f&&(s+=s);while(f);return m}o(Dd,"baseRepeat");function st(s,f){return Sn(Ie(s,f,Di),s+"")}o(st,"baseRest");function ew(s){return wc(jc(s))}o(ew,"baseSample");function Fs(s,f){var m=jc(s);return Vr(m,vl(f,0,m.length))}o(Fs,"baseSampleSize");function Zo(s,f,m,x){if(!Sr(s))return s;f=Gi(f,s);for(var _=-1,L=f.length,F=L-1,z=s;z!=null&&++__?0:_+f),m=m>_?_:m,m<0&&(m+=_),_=f>m?0:m-f>>>0,f>>>=0;for(var L=Q(_);++x<_;)L[x]=s[x+f];return L}o(Li,"baseSlice");function tw(s,f){var m;return di(s,function(x,_,L){return m=f(x,_,L),!m}),!!m}o(tw,"baseSome");function es(s,f,m){var x=0,_=s==null?x:s.length;if(typeof f=="number"&&f===f&&_<=Zt){for(;x<_;){var L=x+_>>>1,F=s[L];F!==null&&!Yi(F)&&(m?F<=f:F=n){var le=f?null:uf(s);if(le)return w(le);F=!1,_=mn,Y=new tn}else Y=f?[]:z;e:for(;++x=x?s:Li(s,f,m)}o(Bs,"castSlice");var Ta=Iy||function(s){return qt.clearTimeout(s)};function Hd(s,f){if(f)return s.slice();var m=s.length,x=Wm?Wm(m):new s.constructor(m);return s.copy(x),x}o(Hd,"cloneBuffer");function Dc(s){var f=new s.constructor(s.byteLength);return new cl(f).set(new cl(s)),f}o(Dc,"cloneArrayBuffer");function nw(s,f){var m=f?Dc(s.buffer):s.buffer;return new s.constructor(m,s.byteOffset,s.byteLength)}o(nw,"cloneDataView");function Wd(s){var f=new s.constructor(s.source,nl.exec(s));return f.lastIndex=s.lastIndex,f}o(Wd,"cloneRegExp");function fg(s){return lr?mt(lr.call(s)):{}}o(fg,"cloneSymbol");function cg(s,f){var m=f?Dc(s.buffer):s.buffer;return new s.constructor(m,s.byteOffset,s.length)}o(cg,"cloneTypedArray");function Ud(s,f){if(s!==f){var m=s!==e,x=s===null,_=s===s,L=Yi(s),F=f!==e,z=f===null,Y=f===f,le=Yi(f);if(!z&&!le&&!L&&s>f||L&&F&&Y&&!z&&!le||x&&F&&Y||!m&&Y||!_)return 1;if(!x&&!L&&!le&&s=z)return Y;var le=m[x];return Y*(le=="desc"?-1:1)}}return s.index-f.index}o(pg,"compareMultiple");function dg(s,f,m,x){for(var _=-1,L=s.length,F=m.length,z=-1,Y=f.length,le=sr(L-F,0),ae=Q(Y+le),ce=!x;++z1?m[_-1]:e,F=_>2?m[2]:e;for(L=s.length>3&&typeof L=="function"?(_--,L):e,F&&b(m[0],m[1],F)&&(L=_<3?e:L,_=1),f=mt(f);++x<_;){var z=m[x];z&&s(f,z,x,L)}return f})}o(ka,"createAssigner");function mg(s,f){return function(m,x){if(m==null)return m;if(!Mi(m))return s(m,x);for(var _=m.length,L=f?_:-1,F=mt(m);(f?L--:++L<_)&&x(F[L],L,F)!==!1;);return m}}o(mg,"createBaseEach");function gg(s){return function(f,m,x){for(var _=-1,L=mt(f),F=x(f),z=F.length;z--;){var Y=F[s?z:++_];if(m(L[Y],Y,L)===!1)break}return f}}o(gg,"createBaseFor");function vg(s,f,m){var x=f&J,_=La(s);function L(){var F=this&&this!==qt&&this instanceof L?_:s;return F.apply(x?m:this,arguments)}return o(L,"wrapper"),L}o(vg,"createBind");function yg(s){return function(f){f=Dt(f);var m=qn(f)?Kt(f):e,x=m?m[0]:f.charAt(0),_=m?Bs(m,1).join(""):f.slice(1);return x[s]()+_}}o(yg,"createCaseFirst");function Na(s){return function(f){return Au(Db(Ab(f).replace(ku,"")),s,"")}}o(Na,"createCompounder");function La(s){return function(){var f=arguments;switch(f.length){case 0:return new s;case 1:return new s(f[0]);case 2:return new s(f[0],f[1]);case 3:return new s(f[0],f[1],f[2]);case 4:return new s(f[0],f[1],f[2],f[3]);case 5:return new s(f[0],f[1],f[2],f[3],f[4]);case 6:return new s(f[0],f[1],f[2],f[3],f[4],f[5]);case 7:return new s(f[0],f[1],f[2],f[3],f[4],f[5],f[6])}var m=go(s.prototype),x=s.apply(m,f);return Sr(x)?x:m}}o(La,"createCtor");function zd(s,f,m){var x=La(s);function _(){for(var L=arguments.length,F=Q(L),z=L,Y=Oa(_);z--;)F[z]=arguments[z];var le=L<3&&F[0]!==Y&&F[L-1]!==Y?[]:Vi(F,Y);if(L-=le.length,L-1?_[L?f[F]:F]:e}}o($d,"createFind");function wg(s){return ts(function(f){var m=f.length,x=m,_=An.prototype.thru;for(s&&f.reverse();x--;){var L=f[x];if(typeof L!="function")throw new Kn(d);if(_&&!F&&cf(L)=="wrapper")var F=new An([],!0)}for(x=F?x:m;++x1&>.reverse(),ae&&Yz))return!1;var le=L.get(s),ae=L.get(f);if(le&&ae)return le==f&&ae==s;var ce=-1,Le=!0,Fe=m&X?new tn:e;for(L.set(s,f),L.set(f,s);++ce1?"& ":"")+f[x],f=f.join(m>2?", ":" "),s.replace(Zf,`{ +`+h.stack}return{value:e,source:t,stack:l,digest:null}}i(rp,"Ji");function M1(e,t,n){return{value:e,source:null,stack:n??null,digest:t??null}}i(M1,"Ki");function hS(e,t){try{console.error(t.value)}catch(n){setTimeout(function(){throw n})}}i(hS,"Li");var N3=typeof WeakMap=="function"?WeakMap:Map;function _N(e,t,n){n=cl(-1,n),n.tag=3,n.payload={element:null};var s=t.value;return n.callback=function(){hy||(hy=!0,ES=s),hS(e,t)},n}i(_N,"Ni");function EN(e,t,n){n=cl(-1,n),n.tag=3;var s=e.type.getDerivedStateFromError;if(typeof s=="function"){var l=t.value;n.payload=function(){return s(l)},n.callback=function(){hS(e,t)}}var h=e.stateNode;return h!==null&&typeof h.componentDidCatch=="function"&&(n.callback=function(){hS(e,t),typeof s!="function"&&(Ru===null?Ru=new Set([this]):Ru.add(this));var d=t.stack;this.componentDidCatch(t.value,{componentStack:d!==null?d:""})}),n}i(EN,"Qi");function DT(e,t,n){var s=e.pingCache;if(s===null){s=e.pingCache=new N3;var l=new Set;s.set(t,l)}else l=s.get(t),l===void 0&&(l=new Set,s.set(t,l));l.has(n)||(l.add(n),e=W3.bind(null,e,t,n),t.then(e,e))}i(DT,"Si");function IT(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}i(IT,"Ui");function FT(e,t,n,s,l){return e.mode&1?(e.flags|=65536,e.lanes=l,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(t=cl(-1,1),t.tag=2,Ou(n,t,1))),n.lanes|=1),e)}i(FT,"Vi");var A3=ml.ReactCurrentOwner,ji=!1;function Ei(e,t,n,s){t.child=e===null?Zk(t,null,n,s):ep(t,e.child,n,s)}i(Ei,"Xi");function BT(e,t,n,s,l){n=n.render;var h=t.ref;return Yd(t,l),s=rx(e,t,n,s,h,l),n=nx(),e!==null&&!ji?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,hl(e,t,l)):(hr&&n&&VS(t),t.flags|=1,Ei(e,t,s,l),t.child)}i(BT,"Yi");function HT(e,t,n,s,l){if(e===null){var h=n.type;return typeof h=="function"&&!px(h)&&h.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(t.tag=15,t.type=h,bN(e,t,h,s,l)):(e=Kv(n.type,null,s,t,t.mode,l),e.ref=t.ref,e.return=t,t.child=e)}if(h=e.child,!(e.lanes&l)){var d=h.memoizedProps;if(n=n.compare,n=n!==null?n:um,n(d,s)&&e.ref===t.ref)return hl(e,t,l)}return t.flags|=1,e=Iu(h,s),e.ref=t.ref,e.return=t,t.child=e}i(HT,"$i");function bN(e,t,n,s,l){if(e!==null){var h=e.memoizedProps;if(um(h,s)&&e.ref===t.ref)if(ji=!1,t.pendingProps=s=h,(e.lanes&l)!==0)e.flags&131072&&(ji=!0);else return t.lanes=e.lanes,hl(e,t,l)}return mS(e,t,n,s,l)}i(bN,"bj");function TN(e,t,n){var s=t.pendingProps,l=s.children,h=e!==null?e.memoizedState:null;if(s.mode==="hidden")if(!(t.mode&1))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},rr(Vd,To),To|=n;else{if(!(n&1073741824))return e=h!==null?h.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,rr(Vd,To),To|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},s=h!==null?h.baseLanes:n,rr(Vd,To),To|=s}else h!==null?(s=h.baseLanes|n,t.memoizedState=null):s=n,rr(Vd,To),To|=s;return Ei(e,t,l,n),t.child}i(TN,"dj");function kN(e,t){var n=t.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}i(kN,"gj");function mS(e,t,n,s,l){var h=Gi(n)?lf:oi.current;return h=Jd(t,h),Yd(t,l),n=rx(e,t,n,s,h,l),s=nx(),e!==null&&!ji?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,hl(e,t,l)):(hr&&s&&VS(t),t.flags|=1,Ei(e,t,n,l),t.child)}i(mS,"cj");function zT(e,t,n,s,l){if(Gi(n)){var h=!0;iy(t)}else h=!1;if(Yd(t,l),t.stateNode===null)Vv(e,t),CN(t,n,s),pS(t,n,s,l),s=!0;else if(e===null){var d=t.stateNode,v=t.memoizedProps;d.props=v;var S=d.context,b=n.contextType;typeof b=="object"&&b!==null?b=as(b):(b=Gi(n)?lf:oi.current,b=Jd(t,b));var k=n.getDerivedStateFromProps,R=typeof k=="function"||typeof d.getSnapshotBeforeUpdate=="function";R||typeof d.UNSAFE_componentWillReceiveProps!="function"&&typeof d.componentWillReceiveProps!="function"||(v!==s||S!==b)&&RT(t,d,s,b),Eu=!1;var I=t.memoizedState;d.state=I,uy(t,s,d,l),S=t.memoizedState,v!==s||I!==S||Ki.current||Eu?(typeof k=="function"&&(dS(t,n,k,s),S=t.memoizedState),(v=Eu||OT(t,n,v,s,I,S,b))?(R||typeof d.UNSAFE_componentWillMount!="function"&&typeof d.componentWillMount!="function"||(typeof d.componentWillMount=="function"&&d.componentWillMount(),typeof d.UNSAFE_componentWillMount=="function"&&d.UNSAFE_componentWillMount()),typeof d.componentDidMount=="function"&&(t.flags|=4194308)):(typeof d.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=s,t.memoizedState=S),d.props=s,d.state=S,d.context=b,s=v):(typeof d.componentDidMount=="function"&&(t.flags|=4194308),s=!1)}else{d=t.stateNode,tN(e,t),v=t.memoizedProps,b=t.type===t.elementType?v:Ms(t.type,v),d.props=b,R=t.pendingProps,I=d.context,S=n.contextType,typeof S=="object"&&S!==null?S=as(S):(S=Gi(n)?lf:oi.current,S=Jd(t,S));var z=n.getDerivedStateFromProps;(k=typeof z=="function"||typeof d.getSnapshotBeforeUpdate=="function")||typeof d.UNSAFE_componentWillReceiveProps!="function"&&typeof d.componentWillReceiveProps!="function"||(v!==R||I!==S)&&RT(t,d,s,S),Eu=!1,I=t.memoizedState,d.state=I,uy(t,s,d,l);var q=t.memoizedState;v!==R||I!==q||Ki.current||Eu?(typeof z=="function"&&(dS(t,n,z,s),q=t.memoizedState),(b=Eu||OT(t,n,b,s,I,q,S)||!1)?(k||typeof d.UNSAFE_componentWillUpdate!="function"&&typeof d.componentWillUpdate!="function"||(typeof d.componentWillUpdate=="function"&&d.componentWillUpdate(s,q,S),typeof d.UNSAFE_componentWillUpdate=="function"&&d.UNSAFE_componentWillUpdate(s,q,S)),typeof d.componentDidUpdate=="function"&&(t.flags|=4),typeof d.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof d.componentDidUpdate!="function"||v===e.memoizedProps&&I===e.memoizedState||(t.flags|=4),typeof d.getSnapshotBeforeUpdate!="function"||v===e.memoizedProps&&I===e.memoizedState||(t.flags|=1024),t.memoizedProps=s,t.memoizedState=q),d.props=s,d.state=q,d.context=S,s=b):(typeof d.componentDidUpdate!="function"||v===e.memoizedProps&&I===e.memoizedState||(t.flags|=4),typeof d.getSnapshotBeforeUpdate!="function"||v===e.memoizedProps&&I===e.memoizedState||(t.flags|=1024),s=!1)}return gS(e,t,n,s,h,l)}i(zT,"hj");function gS(e,t,n,s,l,h){kN(e,t);var d=(t.flags&128)!==0;if(!s&&!d)return l&&bT(t,n,!1),hl(e,t,h);s=t.stateNode,A3.current=t;var v=d&&typeof n.getDerivedStateFromError!="function"?null:s.render();return t.flags|=1,e!==null&&d?(t.child=ep(t,e.child,null,h),t.child=ep(t,null,v,h)):Ei(e,t,v,h),t.memoizedState=s.state,l&&bT(t,n,!0),t.child}i(gS,"jj");function NN(e){var t=e.stateNode;t.pendingContext?ET(e,t.pendingContext,t.pendingContext!==t.context):t.context&&ET(e,t.context,!1),JS(e,t.containerInfo)}i(NN,"kj");function UT(e,t,n,s,l){return Zd(),jS(l),t.flags|=256,Ei(e,t,n,s),t.child}i(UT,"lj");var vS={dehydrated:null,treeContext:null,retryLane:0};function yS(e){return{baseLanes:e,cachePool:null,transitions:null}}i(yS,"nj");function AN(e,t,n){var s=t.pendingProps,l=Er.current,h=!1,d=(t.flags&128)!==0,v;if((v=d)||(v=e!==null&&e.memoizedState===null?!1:(l&2)!==0),v?(h=!0,t.flags&=-129):(e===null||e.memoizedState!==null)&&(l|=1),rr(Er,l&1),e===null)return cS(t),e=t.memoizedState,e!==null&&(e=e.dehydrated,e!==null)?(t.mode&1?e.data==="$!"?t.lanes=8:t.lanes=1073741824:t.lanes=1,null):(d=s.children,e=s.fallback,h?(s=t.mode,h=t.child,d={mode:"hidden",children:d},!(s&1)&&h!==null?(h.childLanes=0,h.pendingProps=d):h=Ny(d,s,0,null),e=af(e,s,n,null),h.return=t,e.return=t,h.sibling=e,t.child=h,t.child.memoizedState=yS(n),t.memoizedState=vS,e):sx(t,d));if(l=e.memoizedState,l!==null&&(v=l.dehydrated,v!==null))return P3(e,t,d,s,v,l,n);if(h){h=s.fallback,d=t.mode,l=e.child,v=l.sibling;var S={mode:"hidden",children:s.children};return!(d&1)&&t.child!==l?(s=t.child,s.childLanes=0,s.pendingProps=S,t.deletions=null):(s=Iu(l,S),s.subtreeFlags=l.subtreeFlags&14680064),v!==null?h=Iu(v,h):(h=af(h,d,n,null),h.flags|=2),h.return=t,s.return=t,s.sibling=h,t.child=s,s=h,h=t.child,d=e.child.memoizedState,d=d===null?yS(n):{baseLanes:d.baseLanes|n,cachePool:null,transitions:d.transitions},h.memoizedState=d,h.childLanes=e.childLanes&~n,t.memoizedState=vS,s}return h=e.child,e=h.sibling,s=Iu(h,{mode:"visible",children:s.children}),!(t.mode&1)&&(s.lanes=n),s.return=t,s.sibling=null,e!==null&&(n=t.deletions,n===null?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=s,t.memoizedState=null,s}i(AN,"oj");function sx(e,t){return t=Ny({mode:"visible",children:t},e.mode,0,null),t.return=e,e.child=t}i(sx,"qj");function Dv(e,t,n,s){return s!==null&&jS(s),ep(t,e.child,null,n),e=sx(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}i(Dv,"sj");function P3(e,t,n,s,l,h,d){if(n)return t.flags&256?(t.flags&=-257,s=M1(Error(ge(422))),Dv(e,t,d,s)):t.memoizedState!==null?(t.child=e.child,t.flags|=128,null):(h=s.fallback,l=t.mode,s=Ny({mode:"visible",children:s.children},l,0,null),h=af(h,l,d,null),h.flags|=2,s.return=t,h.return=t,s.sibling=h,t.child=s,t.mode&1&&ep(t,e.child,null,d),t.child.memoizedState=yS(d),t.memoizedState=vS,h);if(!(t.mode&1))return Dv(e,t,d,null);if(l.data==="$!"){if(s=l.nextSibling&&l.nextSibling.dataset,s)var v=s.dgst;return s=v,h=Error(ge(419)),s=M1(h,s,void 0),Dv(e,t,d,s)}if(v=(d&e.childLanes)!==0,ji||v){if(s=Mn,s!==null){switch(d&-d){case 4:l=2;break;case 16:l=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:l=32;break;case 536870912:l=268435456;break;default:l=0}l=l&(s.suspendedLanes|d)?0:l,l!==0&&l!==h.retryLane&&(h.retryLane=l,pl(e,l),Is(s,e,l,-1))}return dx(),s=M1(Error(ge(421))),Dv(e,t,d,s)}return l.data==="$?"?(t.flags|=128,t.child=e.child,t=$3.bind(null,e),l._reactRetry=t,null):(e=h.treeContext,ko=Mu(l.nextSibling),No=t,hr=!0,Rs=null,e!==null&&(ns[is++]=ll,ns[is++]=ul,ns[is++]=uf,ll=e.id,ul=e.overflow,uf=t),t=sx(t,s.children),t.flags|=4096,t)}i(P3,"rj");function WT(e,t,n){e.lanes|=t;var s=e.alternate;s!==null&&(s.lanes|=t),fS(e.return,t,n)}i(WT,"vj");function O1(e,t,n,s,l){var h=e.memoizedState;h===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:s,tail:n,tailMode:l}:(h.isBackwards=t,h.rendering=null,h.renderingStartTime=0,h.last=s,h.tail=n,h.tailMode=l)}i(O1,"wj");function PN(e,t,n){var s=t.pendingProps,l=s.revealOrder,h=s.tail;if(Ei(e,t,s.children,n),s=Er.current,s&2)s=s&1|2,t.flags|=128;else{if(e!==null&&e.flags&128)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&WT(e,n,t);else if(e.tag===19)WT(e,n,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}s&=1}if(rr(Er,s),!(t.mode&1))t.memoizedState=null;else switch(l){case"forwards":for(n=t.child,l=null;n!==null;)e=n.alternate,e!==null&&cy(e)===null&&(l=n),n=n.sibling;n=l,n===null?(l=t.child,t.child=null):(l=n.sibling,n.sibling=null),O1(t,!1,l,n,h);break;case"backwards":for(n=null,l=t.child,t.child=null;l!==null;){if(e=l.alternate,e!==null&&cy(e)===null){t.child=l;break}e=l.sibling,l.sibling=n,n=l,l=e}O1(t,!0,n,null,h);break;case"together":O1(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}i(PN,"xj");function Vv(e,t){!(t.mode&1)&&e!==null&&(e.alternate=null,t.alternate=null,t.flags|=2)}i(Vv,"ij");function hl(e,t,n){if(e!==null&&(t.dependencies=e.dependencies),ff|=t.lanes,!(n&t.childLanes))return null;if(e!==null&&t.child!==e.child)throw Error(ge(153));if(t.child!==null){for(e=t.child,n=Iu(e,e.pendingProps),t.child=n,n.return=t;e.sibling!==null;)e=e.sibling,n=n.sibling=Iu(e,e.pendingProps),n.return=t;n.sibling=null}return t.child}i(hl,"Zi");function L3(e,t,n){switch(t.tag){case 3:NN(t),Zd();break;case 5:rN(t);break;case 1:Gi(t.type)&&iy(t);break;case 4:JS(t,t.stateNode.containerInfo);break;case 10:var s=t.type._context,l=t.memoizedProps.value;rr(ay,s._currentValue),s._currentValue=l;break;case 13:if(s=t.memoizedState,s!==null)return s.dehydrated!==null?(rr(Er,Er.current&1),t.flags|=128,null):n&t.child.childLanes?AN(e,t,n):(rr(Er,Er.current&1),e=hl(e,t,n),e!==null?e.sibling:null);rr(Er,Er.current&1);break;case 19:if(s=(n&t.childLanes)!==0,e.flags&128){if(s)return PN(e,t,n);t.flags|=128}if(l=t.memoizedState,l!==null&&(l.rendering=null,l.tail=null,l.lastEffect=null),rr(Er,Er.current),s)break;return null;case 22:case 23:return t.lanes=0,TN(e,t,n)}return hl(e,t,n)}i(L3,"yj");var LN,wS,MN,ON;LN=i(function(e,t){for(var n=t.child;n!==null;){if(n.tag===5||n.tag===6)e.appendChild(n.stateNode);else if(n.tag!==4&&n.child!==null){n.child.return=n,n=n.child;continue}if(n===t)break;for(;n.sibling===null;){if(n.return===null||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},"zj");wS=i(function(){},"Aj");MN=i(function(e,t,n,s){var l=e.memoizedProps;if(l!==s){e=t.stateNode,of(Ca.current);var h=null;switch(n){case"input":l=U1(e,l),s=U1(e,s),h=[];break;case"select":l=Tr({},l,{value:void 0}),s=Tr({},s,{value:void 0}),h=[];break;case"textarea":l=V1(e,l),s=V1(e,s),h=[];break;default:typeof l.onClick!="function"&&typeof s.onClick=="function"&&(e.onclick=ry)}j1(n,s);var d;n=null;for(b in l)if(!s.hasOwnProperty(b)&&l.hasOwnProperty(b)&&l[b]!=null)if(b==="style"){var v=l[b];for(d in v)v.hasOwnProperty(d)&&(n||(n={}),n[d]="")}else b!=="dangerouslySetInnerHTML"&&b!=="children"&&b!=="suppressContentEditableWarning"&&b!=="suppressHydrationWarning"&&b!=="autoFocus"&&(rm.hasOwnProperty(b)?h||(h=[]):(h=h||[]).push(b,null));for(b in s){var S=s[b];if(v=l?.[b],s.hasOwnProperty(b)&&S!==v&&(S!=null||v!=null))if(b==="style")if(v){for(d in v)!v.hasOwnProperty(d)||S&&S.hasOwnProperty(d)||(n||(n={}),n[d]="");for(d in S)S.hasOwnProperty(d)&&v[d]!==S[d]&&(n||(n={}),n[d]=S[d])}else n||(h||(h=[]),h.push(b,n)),n=S;else b==="dangerouslySetInnerHTML"?(S=S?S.__html:void 0,v=v?v.__html:void 0,S!=null&&v!==S&&(h=h||[]).push(b,S)):b==="children"?typeof S!="string"&&typeof S!="number"||(h=h||[]).push(b,""+S):b!=="suppressContentEditableWarning"&&b!=="suppressHydrationWarning"&&(rm.hasOwnProperty(b)?(S!=null&&b==="onScroll"&&ur("scroll",e),h||v===S||(h=[])):(h=h||[]).push(b,S))}n&&(h=h||[]).push("style",n);var b=h;(t.updateQueue=b)&&(t.flags|=4)}},"Bj");ON=i(function(e,t,n,s){n!==s&&(t.flags|=4)},"Cj");function zh(e,t){if(!hr)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;t!==null;)t.alternate!==null&&(n=t),t=t.sibling;n===null?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var s=null;n!==null;)n.alternate!==null&&(s=n),n=n.sibling;s===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:s.sibling=null}}i(zh,"Dj");function ni(e){var t=e.alternate!==null&&e.alternate.child===e.child,n=0,s=0;if(t)for(var l=e.child;l!==null;)n|=l.lanes|l.childLanes,s|=l.subtreeFlags&14680064,s|=l.flags&14680064,l.return=e,l=l.sibling;else for(l=e.child;l!==null;)n|=l.lanes|l.childLanes,s|=l.subtreeFlags,s|=l.flags,l.return=e,l=l.sibling;return e.subtreeFlags|=s,e.childLanes=n,t}i(ni,"S");function M3(e,t,n){var s=t.pendingProps;switch(qS(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return ni(t),null;case 1:return Gi(t.type)&&ny(),ni(t),null;case 3:return s=t.stateNode,tp(),cr(Ki),cr(oi),ex(),s.pendingContext&&(s.context=s.pendingContext,s.pendingContext=null),(e===null||e.child===null)&&(Ov(t)?t.flags|=4:e===null||e.memoizedState.isDehydrated&&!(t.flags&256)||(t.flags|=1024,Rs!==null&&(kS(Rs),Rs=null))),wS(e,t),ni(t),null;case 5:ZS(t);var l=of(hm.current);if(n=t.type,e!==null&&t.stateNode!=null)MN(e,t,n,s,l),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!s){if(t.stateNode===null)throw Error(ge(166));return ni(t),null}if(e=of(Ca.current),Ov(t)){s=t.stateNode,n=t.type;var h=t.memoizedProps;switch(s[Sa]=t,s[dm]=h,e=(t.mode&1)!==0,n){case"dialog":ur("cancel",s),ur("close",s);break;case"iframe":case"object":case"embed":ur("load",s);break;case"video":case"audio":for(l=0;l<\/script>",e=e.removeChild(e.firstChild)):typeof s.is=="string"?e=d.createElement(n,{is:s.is}):(e=d.createElement(n),n==="select"&&(d=e,s.multiple?d.multiple=!0:s.size&&(d.size=s.size))):e=d.createElementNS(e,n),e[Sa]=t,e[dm]=s,LN(e,t,!1,!1),t.stateNode=e;e:{switch(d=K1(n,s),n){case"dialog":ur("cancel",e),ur("close",e),l=s;break;case"iframe":case"object":case"embed":ur("load",e),l=s;break;case"video":case"audio":for(l=0;lnp&&(t.flags|=128,s=!0,zh(h,!1),t.lanes=4194304)}else{if(!s)if(e=cy(d),e!==null){if(t.flags|=128,s=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),zh(h,!0),h.tail===null&&h.tailMode==="hidden"&&!d.alternate&&!hr)return ni(t),null}else 2*$r()-h.renderingStartTime>np&&n!==1073741824&&(t.flags|=128,s=!0,zh(h,!1),t.lanes=4194304);h.isBackwards?(d.sibling=t.child,t.child=d):(n=h.last,n!==null?n.sibling=d:t.child=d,h.last=d)}return h.tail!==null?(t=h.tail,h.rendering=t,h.tail=t.sibling,h.renderingStartTime=$r(),t.sibling=null,n=Er.current,rr(Er,s?n&1|2:n&1),t):(ni(t),null);case 22:case 23:return fx(),s=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==s&&(t.flags|=8192),s&&t.mode&1?To&1073741824&&(ni(t),t.subtreeFlags&6&&(t.flags|=8192)):ni(t),null;case 24:return null;case 25:return null}throw Error(ge(156,t.tag))}i(M3,"Ej");function O3(e,t){switch(qS(t),t.tag){case 1:return Gi(t.type)&&ny(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return tp(),cr(Ki),cr(oi),ex(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return ZS(t),null;case 13:if(cr(Er),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(ge(340));Zd()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return cr(Er),null;case 4:return tp(),null;case 10:return YS(t.type._context),null;case 22:case 23:return fx(),null;case 24:return null;default:return null}}i(O3,"Ij");var Iv=!1,ii=!1,R3=typeof WeakSet=="function"?WeakSet:Set,Le=null;function $d(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(s){Mr(e,t,s)}else n.current=null}i($d,"Lj");function SS(e,t,n){try{n()}catch(s){Mr(e,t,s)}}i(SS,"Mj");var $T=!1;function D3(e,t){if(nS=Zv,e=Bk(),$S(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var s=n.getSelection&&n.getSelection();if(s&&s.rangeCount!==0){n=s.anchorNode;var l=s.anchorOffset,h=s.focusNode;s=s.focusOffset;try{n.nodeType,h.nodeType}catch{n=null;break e}var d=0,v=-1,S=-1,b=0,k=0,R=e,I=null;t:for(;;){for(var z;R!==n||l!==0&&R.nodeType!==3||(v=d+l),R!==h||s!==0&&R.nodeType!==3||(S=d+s),R.nodeType===3&&(d+=R.nodeValue.length),(z=R.firstChild)!==null;)I=R,R=z;for(;;){if(R===e)break t;if(I===n&&++b===l&&(v=d),I===h&&++k===s&&(S=d),(z=R.nextSibling)!==null)break;R=I,I=R.parentNode}R=z}n=v===-1||S===-1?null:{start:v,end:S}}else n=null}n=n||{start:0,end:0}}else n=null;for(iS={focusedElem:e,selectionRange:n},Zv=!1,Le=t;Le!==null;)if(t=Le,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,Le=e;else for(;Le!==null;){t=Le;try{var q=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(q!==null){var Q=q.memoizedProps,ne=q.memoizedState,D=t.stateNode,L=D.getSnapshotBeforeUpdate(t.elementType===t.type?Q:Ms(t.type,Q),ne);D.__reactInternalSnapshotBeforeUpdate=L}break;case 3:var B=t.stateNode.containerInfo;B.nodeType===1?B.textContent="":B.nodeType===9&&B.documentElement&&B.removeChild(B.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(ge(163))}}catch(j){Mr(t,t.return,j)}if(e=t.sibling,e!==null){e.return=t.return,Le=e;break}Le=t.return}return q=$T,$T=!1,q}i(D3,"Oj");function Zh(e,t,n){var s=t.updateQueue;if(s=s!==null?s.lastEffect:null,s!==null){var l=s=s.next;do{if((l.tag&e)===e){var h=l.destroy;l.destroy=void 0,h!==void 0&&SS(t,n,h)}l=l.next}while(l!==s)}}i(Zh,"Pj");function Ty(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var s=n.create;n.destroy=s()}n=n.next}while(n!==t)}}i(Ty,"Qj");function xS(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}i(xS,"Rj");function RN(e){var t=e.alternate;t!==null&&(e.alternate=null,RN(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Sa],delete t[dm],delete t[aS],delete t[v3],delete t[y3])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}i(RN,"Sj");function DN(e){return e.tag===5||e.tag===3||e.tag===4}i(DN,"Tj");function VT(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||DN(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}i(VT,"Uj");function CS(e,t,n){var s=e.tag;if(s===5||s===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=ry));else if(s!==4&&(e=e.child,e!==null))for(CS(e,t,n),e=e.sibling;e!==null;)CS(e,t,n),e=e.sibling}i(CS,"Vj");function _S(e,t,n){var s=e.tag;if(s===5||s===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(s!==4&&(e=e.child,e!==null))for(_S(e,t,n),e=e.sibling;e!==null;)_S(e,t,n),e=e.sibling}i(_S,"Wj");var Vn=null,Os=!1;function Cu(e,t,n){for(n=n.child;n!==null;)IN(e,t,n),n=n.sibling}i(Cu,"Yj");function IN(e,t,n){if(xa&&typeof xa.onCommitFiberUnmount=="function")try{xa.onCommitFiberUnmount(yy,n)}catch{}switch(n.tag){case 5:ii||$d(n,t);case 6:var s=Vn,l=Os;Vn=null,Cu(e,t,n),Vn=s,Os=l,Vn!==null&&(Os?(e=Vn,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Vn.removeChild(n.stateNode));break;case 18:Vn!==null&&(Os?(e=Vn,n=n.stateNode,e.nodeType===8?T1(e.parentNode,n):e.nodeType===1&&T1(e,n),am(e)):T1(Vn,n.stateNode));break;case 4:s=Vn,l=Os,Vn=n.stateNode.containerInfo,Os=!0,Cu(e,t,n),Vn=s,Os=l;break;case 0:case 11:case 14:case 15:if(!ii&&(s=n.updateQueue,s!==null&&(s=s.lastEffect,s!==null))){l=s=s.next;do{var h=l,d=h.destroy;h=h.tag,d!==void 0&&(h&2||h&4)&&SS(n,t,d),l=l.next}while(l!==s)}Cu(e,t,n);break;case 1:if(!ii&&($d(n,t),s=n.stateNode,typeof s.componentWillUnmount=="function"))try{s.props=n.memoizedProps,s.state=n.memoizedState,s.componentWillUnmount()}catch(v){Mr(n,t,v)}Cu(e,t,n);break;case 21:Cu(e,t,n);break;case 22:n.mode&1?(ii=(s=ii)||n.memoizedState!==null,Cu(e,t,n),ii=s):Cu(e,t,n);break;default:Cu(e,t,n)}}i(IN,"Zj");function qT(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new R3),t.forEach(function(s){var l=V3.bind(null,e,s);n.has(s)||(n.add(s),s.then(l,l))})}}i(qT,"ak");function Ls(e,t){var n=t.deletions;if(n!==null)for(var s=0;sl&&(l=d),s&=~h}if(s=l,s=$r()-s,s=(120>s?120:480>s?480:1080>s?1080:1920>s?1920:3e3>s?3e3:4320>s?4320:1960*F3(s/1960))-s,10e?16:e,Nu===null)var s=!1;else{if(e=Nu,Nu=null,my=0,Nt&6)throw Error(ge(331));var l=Nt;for(Nt|=4,Le=e.current;Le!==null;){var h=Le,d=h.child;if(Le.flags&16){var v=h.deletions;if(v!==null){for(var S=0;S$r()-ux?sf(e,0):lx|=n),Yi(e,t)}i(W3,"Ti");function VN(e,t){t===0&&(e.mode&1?(t=_v,_v<<=1,!(_v&130023424)&&(_v=4194304)):t=1);var n=bi();e=pl(e,t),e!==null&&(wm(e,t,n),Yi(e,n))}i(VN,"Yk");function $3(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),VN(e,n)}i($3,"uj");function V3(e,t){var n=0;switch(e.tag){case 13:var s=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:s=e.stateNode;break;default:throw Error(ge(314))}s!==null&&s.delete(t),VN(e,n)}i(V3,"bk");var qN;qN=i(function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Ki.current)ji=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return ji=!1,L3(e,t,n);ji=!!(e.flags&131072)}else ji=!1,hr&&t.flags&1048576&&Yk(t,sy,t.index);switch(t.lanes=0,t.tag){case 2:var s=t.type;Vv(e,t),e=t.pendingProps;var l=Jd(t,oi.current);Yd(t,n),l=rx(null,t,s,e,l,n);var h=nx();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Gi(s)?(h=!0,iy(t)):h=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,QS(t),l.updater=by,t.stateNode=l,l._reactInternals=t,pS(t,s,e,n),t=gS(null,t,s,!0,h,n)):(t.tag=0,hr&&h&&VS(t),Ei(null,t,l,n),t=t.child),t;case 16:s=t.elementType;e:{switch(Vv(e,t),e=t.pendingProps,l=s._init,s=l(s._payload),t.type=s,l=t.tag=j3(s),e=Ms(s,e),l){case 0:t=mS(null,t,s,e,n);break e;case 1:t=zT(null,t,s,e,n);break e;case 11:t=BT(null,t,s,e,n);break e;case 14:t=HT(null,t,s,Ms(s.type,e),n);break e}throw Error(ge(306,s,""))}return t;case 0:return s=t.type,l=t.pendingProps,l=t.elementType===s?l:Ms(s,l),mS(e,t,s,l,n);case 1:return s=t.type,l=t.pendingProps,l=t.elementType===s?l:Ms(s,l),zT(e,t,s,l,n);case 3:e:{if(NN(t),e===null)throw Error(ge(387));s=t.pendingProps,h=t.memoizedState,l=h.element,tN(e,t),uy(t,s,null,n);var d=t.memoizedState;if(s=d.element,h.isDehydrated)if(h={element:s,isDehydrated:!1,cache:d.cache,pendingSuspenseBoundaries:d.pendingSuspenseBoundaries,transitions:d.transitions},t.updateQueue.baseState=h,t.memoizedState=h,t.flags&256){l=rp(Error(ge(423)),t),t=UT(e,t,s,n,l);break e}else if(s!==l){l=rp(Error(ge(424)),t),t=UT(e,t,s,n,l);break e}else for(ko=Mu(t.stateNode.containerInfo.firstChild),No=t,hr=!0,Rs=null,n=Zk(t,null,s,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(Zd(),s===l){t=hl(e,t,n);break e}Ei(e,t,s,n)}t=t.child}return t;case 5:return rN(t),e===null&&cS(t),s=t.type,l=t.pendingProps,h=e!==null?e.memoizedProps:null,d=l.children,oS(s,l)?d=null:h!==null&&oS(s,h)&&(t.flags|=32),kN(e,t),Ei(e,t,d,n),t.child;case 6:return e===null&&cS(t),null;case 13:return AN(e,t,n);case 4:return JS(t,t.stateNode.containerInfo),s=t.pendingProps,e===null?t.child=ep(t,null,s,n):Ei(e,t,s,n),t.child;case 11:return s=t.type,l=t.pendingProps,l=t.elementType===s?l:Ms(s,l),BT(e,t,s,l,n);case 7:return Ei(e,t,t.pendingProps,n),t.child;case 8:return Ei(e,t,t.pendingProps.children,n),t.child;case 12:return Ei(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(s=t.type._context,l=t.pendingProps,h=t.memoizedProps,d=l.value,rr(ay,s._currentValue),s._currentValue=d,h!==null)if(Fs(h.value,d)){if(h.children===l.children&&!Ki.current){t=hl(e,t,n);break e}}else for(h=t.child,h!==null&&(h.return=t);h!==null;){var v=h.dependencies;if(v!==null){d=h.child;for(var S=v.firstContext;S!==null;){if(S.context===s){if(h.tag===1){S=cl(-1,n&-n),S.tag=2;var b=h.updateQueue;if(b!==null){b=b.shared;var k=b.pending;k===null?S.next=S:(S.next=k.next,k.next=S),b.pending=S}}h.lanes|=n,S=h.alternate,S!==null&&(S.lanes|=n),fS(h.return,n,t),v.lanes|=n;break}S=S.next}}else if(h.tag===10)d=h.type===t.type?null:h.child;else if(h.tag===18){if(d=h.return,d===null)throw Error(ge(341));d.lanes|=n,v=d.alternate,v!==null&&(v.lanes|=n),fS(d,n,t),d=h.sibling}else d=h.child;if(d!==null)d.return=h;else for(d=h;d!==null;){if(d===t){d=null;break}if(h=d.sibling,h!==null){h.return=d.return,d=h;break}d=d.return}h=d}Ei(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,s=t.pendingProps.children,Yd(t,n),l=as(l),s=s(l),t.flags|=1,Ei(e,t,s,n),t.child;case 14:return s=t.type,l=Ms(s,t.pendingProps),l=Ms(s.type,l),HT(e,t,s,l,n);case 15:return bN(e,t,t.type,t.pendingProps,n);case 17:return s=t.type,l=t.pendingProps,l=t.elementType===s?l:Ms(s,l),Vv(e,t),t.tag=1,Gi(s)?(e=!0,iy(t)):e=!1,Yd(t,n),CN(t,s,l),pS(t,s,l,n),gS(null,t,s,!0,e,n);case 19:return PN(e,t,n);case 22:return TN(e,t,n)}throw Error(ge(156,t.tag))},"Vk");function jN(e,t){return wk(e,t)}i(jN,"Fk");function q3(e,t,n,s){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=s,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}i(q3,"$k");function os(e,t,n,s){return new q3(e,t,n,s)}i(os,"Bg");function px(e){return e=e.prototype,!(!e||!e.isReactComponent)}i(px,"aj");function j3(e){if(typeof e=="function")return px(e)?1:0;if(e!=null){if(e=e.$$typeof,e===MS)return 11;if(e===OS)return 14}return 2}i(j3,"Zk");function Iu(e,t){var n=e.alternate;return n===null?(n=os(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}i(Iu,"Pg");function Kv(e,t,n,s,l,h){var d=2;if(s=e,typeof e=="function")px(e)&&(d=1);else if(typeof e=="string")d=5;else e:switch(e){case Rd:return af(n.children,l,h,t);case LS:d=8,l|=8;break;case F1:return e=os(12,n,t,l|2),e.elementType=F1,e.lanes=h,e;case B1:return e=os(13,n,t,l),e.elementType=B1,e.lanes=h,e;case H1:return e=os(19,n,t,l),e.elementType=H1,e.lanes=h,e;case rk:return Ny(n,l,h,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case ek:d=10;break e;case tk:d=9;break e;case MS:d=11;break e;case OS:d=14;break e;case _u:d=16,s=null;break e}throw Error(ge(130,e==null?e:typeof e,""))}return t=os(d,n,t,l),t.elementType=e,t.type=s,t.lanes=h,t}i(Kv,"Rg");function af(e,t,n,s){return e=os(7,e,s,t),e.lanes=n,e}i(af,"Tg");function Ny(e,t,n,s){return e=os(22,e,s,t),e.elementType=rk,e.lanes=n,e.stateNode={isHidden:!1},e}i(Ny,"pj");function R1(e,t,n){return e=os(6,e,null,t),e.lanes=n,e}i(R1,"Qg");function D1(e,t,n){return t=os(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}i(D1,"Sg");function K3(e,t,n,s,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=y1(0),this.expirationTimes=y1(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=y1(0),this.identifierPrefix=s,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}i(K3,"al");function hx(e,t,n,s,l,h,d,v,S){return e=new K3(e,t,n,v,S),t===1?(t=1,h===!0&&(t|=8)):t=0,h=os(3,null,null,t),e.current=h,h.stateNode=e,h.memoizedState={element:s,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},QS(h),e}i(hx,"bl");function G3(e,t,n){var s=3{"use strict";function QN(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(QN)}catch(e){console.error(e)}}i(QN,"checkDCE");QN(),JN.exports=XN()});var eA=rt(wx=>{"use strict";var ZN=yx();wx.createRoot=ZN.createRoot,wx.hydrateRoot=ZN.hydrateRoot;var HW});var rA=rt(tA=>{"use strict";var _m=Te();function Z3(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}i(Z3,"n");var e4=typeof Object.is=="function"?Object.is:Z3,t4=_m.useSyncExternalStore,r4=_m.useRef,n4=_m.useEffect,i4=_m.useMemo,o4=_m.useDebugValue;tA.useSyncExternalStoreWithSelector=function(e,t,n,s,l){var h=r4(null);if(h.current===null){var d={hasValue:!1,value:null};h.current=d}else d=h.current;h=i4(function(){function S(z){if(!b){if(b=!0,k=z,z=s(z),l!==void 0&&d.hasValue){var q=d.value;if(l(q,z))return R=q}return R=z}if(q=R,e4(k,z))return q;var Q=s(z);return l!==void 0&&l(q,Q)?q:(k=z,R=Q)}i(S,"a");var b=!1,k,R,I=n===void 0?null:n;return[function(){return S(t())},I===null?void 0:function(){return S(I())}]},[t,n,s,l]);var v=t4(e,h[0],h[1]);return n4(function(){d.hasValue=!0,d.value=v},[v]),o4(v),v}});var iA=rt(($W,nA)=>{"use strict";nA.exports=rA()});var bm=rt((sp,Em)=>{(function(){var e,t="4.17.21",n=200,s="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",l="Expected a function",h="Invalid `variable` option passed into `_.template`",d="__lodash_hash_undefined__",v=500,S="__lodash_placeholder__",b=1,k=2,R=4,I=1,z=2,q=1,Q=2,ne=4,D=8,L=16,B=32,j=64,re=128,Z=256,oe=512,he=30,Re="...",Ee=800,Ye=16,tt=1,xe=2,Xe=3,je=1/0,Qe=9007199254740991,ot=17976931348623157e292,It=NaN,At=4294967295,cn=At-1,fn=At>>>1,gr=[["ary",re],["bind",q],["bindKey",Q],["curry",D],["curryRight",L],["flip",oe],["partial",B],["partialRight",j],["rearg",Z]],Wt="[object Arguments]",vr="[object Array]",yr="[object AsyncFunction]",Gt="[object Boolean]",Ft="[object Date]",se="[object DOMException]",Ue="[object Error]",Kr="[object Function]",Zt="[object GeneratorFunction]",st="[object Map]",Fe="[object Number]",Fn="[object Null]",En="[object Object]",no="[object Promise]",Ho="[object Proxy]",lt="[object RegExp]",wr="[object Set]",fr="[object String]",pt="[object Symbol]",io="[object Undefined]",Bn="[object WeakMap]",Mi="[object WeakSet]",Gr="[object ArrayBuffer]",Yr="[object DataView]",oo="[object Float32Array]",hi="[object Float64Array]",Hn="[object Int8Array]",so="[object Int16Array]",bl="[object Int32Array]",Y="[object Uint8Array]",ee="[object Uint8ClampedArray]",Ce="[object Uint16Array]",Me="[object Uint32Array]",Tl=/\b__p \+= '';/g,ze=/\b(__p \+=) '' \+/g,Xr=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Yt=/&(?:amp|lt|gt|quot|#39);/g,Mt=/[&<>"']/g,Pt=RegExp(Yt.source),Na=RegExp(Mt.source),dn=/<%-([\s\S]+?)%>/g,zn=/<%([\s\S]+?)%>/g,kr=/<%=([\s\S]+?)%>/g,gs=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,bn=/^\w*$/,Aa=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Pa=/[\\^$.*+?()[\]{}|]/g,nc=RegExp(Pa.source),ic=/^\s+/,oc=/\s/,$f=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,sc=/\{\n\/\* \[wrapped with (.+)\] \*/,Fp=/,? & /,kl=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,Bp=/[()=,{}\[\]\/\s]/,Hp=/\\(\\)?/g,Nl=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,Vf=/\w*$/,ac=/^[-+]0x[0-9a-f]+$/i,vs=/^0b[01]+$/i,zp=/^\[object .+?Constructor\]$/,Up=/^0o[0-7]+$/i,La=/^(?:0|[1-9]\d*)$/,lc=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,ao=/($^)/,qf=/['\n\r\u2028\u2029\\]/g,Oi="\\ud800-\\udfff",uc="\\u0300-\\u036f",cc="\\ufe20-\\ufe2f",or="\\u20d0-\\u20ff",Pe=uc+cc+or,lo="\\u2700-\\u27bf",Al="a-z\\xdf-\\xf6\\xf8-\\xff",Ri="\\xac\\xb1\\xd7\\xf7",vt="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",ys="\\u2000-\\u206f",Ma=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Oa="A-Z\\xc0-\\xd6\\xd8-\\xde",ce="\\ufe0e\\ufe0f",Ve=Ri+vt+ys+Ma,qs="['\u2019]",fc="["+Oi+"]",js="["+Ve+"]",zo="["+Pe+"]",dc="\\d+",qe="["+lo+"]",jf="["+Al+"]",Pl="[^"+Oi+Ve+dc+lo+Al+Oa+"]",ws="\\ud83c[\\udffb-\\udfff]",mi="(?:"+zo+"|"+ws+")",Ll="[^"+Oi+"]",Ml="(?:\\ud83c[\\udde6-\\uddff]){2}",Ss="[\\ud800-\\udbff][\\udc00-\\udfff]",uo="["+Oa+"]",Ol="\\u200d",Ks="(?:"+jf+"|"+Pl+")",pc="(?:"+uo+"|"+Pl+")",Rl="(?:"+qs+"(?:d|ll|m|re|s|t|ve))?",hc="(?:"+qs+"(?:D|LL|M|RE|S|T|VE))?",mc=mi+"?",Dl="["+ce+"]?",Ra="(?:"+Ol+"(?:"+[Ll,Ml,Ss].join("|")+")"+Dl+mc+")*",gc="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Di="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",Kf=Dl+mc+Ra,Wp="(?:"+[qe,Ml,Ss].join("|")+")"+Kf,Il="(?:"+[Ll+zo+"?",zo,Ml,Ss,fc].join("|")+")",Da=RegExp(qs,"g"),$p=RegExp(zo,"g"),vc=RegExp(ws+"(?="+ws+")|"+Il+Kf,"g"),Vp=RegExp([uo+"?"+jf+"+"+Rl+"(?="+[js,uo,"$"].join("|")+")",pc+"+"+hc+"(?="+[js,uo+Ks,"$"].join("|")+")",uo+"?"+Ks+"+"+Rl,uo+"+"+hc,Di,gc,dc,Wp].join("|"),"g"),qp=RegExp("["+Ol+Oi+Pe+ce+"]"),yc=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Gf=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],jp=-1,Bt={};Bt[oo]=Bt[hi]=Bt[Hn]=Bt[so]=Bt[bl]=Bt[Y]=Bt[ee]=Bt[Ce]=Bt[Me]=!0,Bt[Wt]=Bt[vr]=Bt[Gr]=Bt[Gt]=Bt[Yr]=Bt[Ft]=Bt[Ue]=Bt[Kr]=Bt[st]=Bt[Fe]=Bt[En]=Bt[lt]=Bt[wr]=Bt[fr]=Bt[Bn]=!1;var Ot={};Ot[Wt]=Ot[vr]=Ot[Gr]=Ot[Yr]=Ot[Gt]=Ot[Ft]=Ot[oo]=Ot[hi]=Ot[Hn]=Ot[so]=Ot[bl]=Ot[st]=Ot[Fe]=Ot[En]=Ot[lt]=Ot[wr]=Ot[fr]=Ot[pt]=Ot[Y]=Ot[ee]=Ot[Ce]=Ot[Me]=!0,Ot[Ue]=Ot[Kr]=Ot[Bn]=!1;var M={\u00C0:"A",\u00C1:"A",\u00C2:"A",\u00C3:"A",\u00C4:"A",\u00C5:"A",\u00E0:"a",\u00E1:"a",\u00E2:"a",\u00E3:"a",\u00E4:"a",\u00E5:"a",\u00C7:"C",\u00E7:"c",\u00D0:"D",\u00F0:"d",\u00C8:"E",\u00C9:"E",\u00CA:"E",\u00CB:"E",\u00E8:"e",\u00E9:"e",\u00EA:"e",\u00EB:"e",\u00CC:"I",\u00CD:"I",\u00CE:"I",\u00CF:"I",\u00EC:"i",\u00ED:"i",\u00EE:"i",\u00EF:"i",\u00D1:"N",\u00F1:"n",\u00D2:"O",\u00D3:"O",\u00D4:"O",\u00D5:"O",\u00D6:"O",\u00D8:"O",\u00F2:"o",\u00F3:"o",\u00F4:"o",\u00F5:"o",\u00F6:"o",\u00F8:"o",\u00D9:"U",\u00DA:"U",\u00DB:"U",\u00DC:"U",\u00F9:"u",\u00FA:"u",\u00FB:"u",\u00FC:"u",\u00DD:"Y",\u00FD:"y",\u00FF:"y",\u00C6:"Ae",\u00E6:"ae",\u00DE:"Th",\u00FE:"th",\u00DF:"ss",\u0100:"A",\u0102:"A",\u0104:"A",\u0101:"a",\u0103:"a",\u0105:"a",\u0106:"C",\u0108:"C",\u010A:"C",\u010C:"C",\u0107:"c",\u0109:"c",\u010B:"c",\u010D:"c",\u010E:"D",\u0110:"D",\u010F:"d",\u0111:"d",\u0112:"E",\u0114:"E",\u0116:"E",\u0118:"E",\u011A:"E",\u0113:"e",\u0115:"e",\u0117:"e",\u0119:"e",\u011B:"e",\u011C:"G",\u011E:"G",\u0120:"G",\u0122:"G",\u011D:"g",\u011F:"g",\u0121:"g",\u0123:"g",\u0124:"H",\u0126:"H",\u0125:"h",\u0127:"h",\u0128:"I",\u012A:"I",\u012C:"I",\u012E:"I",\u0130:"I",\u0129:"i",\u012B:"i",\u012D:"i",\u012F:"i",\u0131:"i",\u0134:"J",\u0135:"j",\u0136:"K",\u0137:"k",\u0138:"k",\u0139:"L",\u013B:"L",\u013D:"L",\u013F:"L",\u0141:"L",\u013A:"l",\u013C:"l",\u013E:"l",\u0140:"l",\u0142:"l",\u0143:"N",\u0145:"N",\u0147:"N",\u014A:"N",\u0144:"n",\u0146:"n",\u0148:"n",\u014B:"n",\u014C:"O",\u014E:"O",\u0150:"O",\u014D:"o",\u014F:"o",\u0151:"o",\u0154:"R",\u0156:"R",\u0158:"R",\u0155:"r",\u0157:"r",\u0159:"r",\u015A:"S",\u015C:"S",\u015E:"S",\u0160:"S",\u015B:"s",\u015D:"s",\u015F:"s",\u0161:"s",\u0162:"T",\u0164:"T",\u0166:"T",\u0163:"t",\u0165:"t",\u0167:"t",\u0168:"U",\u016A:"U",\u016C:"U",\u016E:"U",\u0170:"U",\u0172:"U",\u0169:"u",\u016B:"u",\u016D:"u",\u016F:"u",\u0171:"u",\u0173:"u",\u0174:"W",\u0175:"w",\u0176:"Y",\u0177:"y",\u0178:"Y",\u0179:"Z",\u017B:"Z",\u017D:"Z",\u017A:"z",\u017C:"z",\u017E:"z",\u0132:"IJ",\u0133:"ij",\u0152:"Oe",\u0153:"oe",\u0149:"'n",\u017F:"s"},De={"&":"&","<":"<",">":">",'"':""","'":"'"},Gs={"&":"&","<":"<",">":">",""":'"',"'":"'"},gi={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Fl=parseFloat,ve=parseInt,Ia=typeof global=="object"&&global&&global.Object===Object&&global,Kp=typeof self=="object"&&self&&self.Object===Object&&self,Rt=Ia||Kp||Function("return this")(),Yf=typeof sp=="object"&&sp&&!sp.nodeType&&sp,Ys=Yf&&typeof Em=="object"&&Em&&!Em.nodeType&&Em,Fa=Ys&&Ys.exports===Yf,Uo=Fa&&Ia.process,Se=function(){try{var G=Ys&&Ys.require&&Ys.require("util").types;return G||Uo&&Uo.binding&&Uo.binding("util")}catch{}}(),Xs=Se&&Se.isArrayBuffer,vi=Se&&Se.isDate,Ze=Se&&Se.isMap,Bl=Se&&Se.isRegExp,pn=Se&&Se.isSet,Hl=Se&&Se.isTypedArray;function Qr(G,ie,J){switch(J.length){case 0:return G.call(ie);case 1:return G.call(ie,J[0]);case 2:return G.call(ie,J[0],J[1]);case 3:return G.call(ie,J[0],J[1],J[2])}return G.apply(ie,J)}i(Qr,"apply");function zl(G,ie,J,Ae){for(var Je=-1,yt=G==null?0:G.length;++Je-1}i(Ba,"arrayIncludes");function Ul(G,ie,J){for(var Ae=-1,Je=G==null?0:G.length;++Ae-1;);return J}i(yi,"charsStartIndex");function ea(G,ie){for(var J=G.length;J--&&Kt(ie,G[J],0)>-1;);return J}i(ea,"charsEndIndex");function ql(G,ie){for(var J=G.length,Ae=0;J--;)G[J]===ie&&++Ae;return Ae}i(ql,"countHolders");var Tc=Ha(M),Fi=Ha(De);function $o(G){return"\\"+gi[G]}i($o,"escapeStringChar");function jl(G,ie){return G==null?e:G[ie]}i(jl,"getValue");function xs(G){return qp.test(G)}i(xs,"hasUnicode");function td(G){return yc.test(G)}i(td,"hasUnicodeWord");function Xp(G){for(var ie,J=[];!(ie=G.next()).done;)J.push(ie.value);return J}i(Xp,"iteratorToArray");function Kl(G){var ie=-1,J=Array(G.size);return G.forEach(function(Ae,Je){J[++ie]=[Je,Ae]}),J}i(Kl,"mapToArray");function Gl(G,ie){return function(J){return G(ie(J))}}i(Gl,"overArg");function Tn(G,ie){for(var J=-1,Ae=G.length,Je=0,yt=[];++J-1}i(Sg,"listCacheHas");function xg(a,f){var m=this.__data__,x=tu(m,a);return x<0?(++this.size,m.push([a,f])):m[x][1]=f,this}i(xg,"listCacheSet"),vo.prototype.clear=Sw,vo.prototype.delete=oh,vo.prototype.get=sh,vo.prototype.has=Sg,vo.prototype.set=xg;function yo(a){var f=-1,m=a==null?0:a.length;for(this.clear();++f=f?a:f)),a}i(Ts,"baseClamp");function wi(a,f,m,x,T,P){var H,$=f&b,X=f&k,le=f&R;if(m&&(H=T?m(a,x,T,P):m(a)),H!==e)return H;if(!_r(a))return a;var ue=at(a);if(ue){if(H=Bw(a),!$)return ei(a,H)}else{var fe=Hr(a),Ne=fe==Kr||fe==Zt;if(Su(a))return Sh(a,$);if(fe==En||fe==Wt||Ne&&!T){if(H=X||Ne?{}:tv(a),!$)return X?Ow(a,bg(H,a)):qg(a,uh(H,a))}else{if(!Ot[fe])return T?a:{};H=kd(a,fe,$)}}P||(P=new sr);var He=P.get(a);if(He)return He;P.set(a,H),sb(a)?a.forEach(function(Ge){H.add(wi(Ge,f,m,Ge,a,P))}):ib(a)&&a.forEach(function(Ge,ht){H.set(ht,wi(Ge,f,m,ht,a,P))});var Ke=le?X?Td:bd:X?$i:Pn,dt=ue?e:Ke(a);return Zn(dt||a,function(Ge,ht){dt&&(ht=Ge,Ge=a[ht]),eu(H,ht,wi(Ge,f,m,ht,a,P))}),H}i(wi,"baseClone");function Ew(a){var f=Pn(a);return function(m){return ch(m,a,f)}}i(Ew,"baseConforms");function ch(a,f,m){var x=m.length;if(a==null)return!x;for(a=Ht(a);x--;){var T=m[x],P=f[T],H=a[T];if(H===e&&!(T in a)||!P(H))return!1}return!0}i(ch,"baseConformsTo");function Tg(a,f,m){if(typeof a!="function")throw new Bi(l);return Ie(function(){a.apply(e,m)},f)}i(Tg,"baseDelay");function Dc(a,f,m,x){var T=-1,P=Ba,H=!0,$=a.length,X=[],le=f.length;if(!$)return X;m&&(f=$t(f,hn(m))),x?(P=Ul,H=!1):f.length>=n&&(P=co,H=!1,f=new ia(f));e:for(;++T<$;){var ue=a[T],fe=m==null?ue:m(ue);if(ue=x||ue!==0?ue:0,H&&fe===fe){for(var Ne=le;Ne--;)if(f[Ne]===fe)continue e;X.push(ue)}else P(f,fe,x)||X.push(ue)}return X}i(Dc,"baseDifference");var So=hu(zi),fh=hu(pd,!0);function bw(a,f){var m=!0;return So(a,function(x,T,P){return m=!!f(x,T,P),m}),m}i(bw,"baseEvery");function dd(a,f,m){for(var x=-1,T=a.length;++xT?0:T+m),x=x===e||x>T?T:ct(x),x<0&&(x+=T),x=m>x?0:lb(x);m0&&m($)?f>1?Fr($,f-1,m,x,T):Ii(T,$):x||(T[T.length]=$)}return T}i(Fr,"baseFlatten");var nu=jg(),dh=jg(!0);function zi(a,f){return a&&nu(a,f,Pn)}i(zi,"baseForOwn");function pd(a,f){return a&&dh(a,f,Pn)}i(pd,"baseForOwnRight");function hd(a,f){return jt(f,function(m){return nl(a[m])})}i(hd,"baseFunctions");function la(a,f){f=fa(f,a);for(var m=0,x=f.length;a!=null&&mf}i(md,"baseGt");function Ng(a,f){return a!=null&&kt.call(a,f)}i(Ng,"baseHas");function Ag(a,f){return a!=null&&f in Ht(a)}i(Ag,"baseHasIn");function iu(a,f,m){return a>=Ar(f,m)&&a=120&&ue.length>=120)?new ia(H&&ue):e}ue=a[0];var fe=-1,Ne=$[0];e:for(;++fe-1;)$!==a&&Wa.call($,X,1),Wa.call(a,X,1);return a}i(vh,"basePullAll");function kn(a,f){for(var m=a?f.length:0,x=m-1;m--;){var T=f[m];if(m==x||T!==P){var P=T;c(T)?Wa.call(a,T,1):vd(a,T)}}return a}i(kn,"basePullAt");function gd(a,f){return a+Va(nh()*(f-a+1))}i(gd,"baseRandom");function kw(a,f,m,x){for(var T=-1,P=er(Ac((f-a)/(m||1)),0),H=J(P);P--;)H[x?P:++T]=a,a+=m;return H}i(kw,"baseRange");function yh(a,f){var m="";if(!a||f<1||f>Qe)return m;do f%2&&(m+=a),f=Va(f/2),f&&(a+=a);while(f);return m}i(yh,"baseRepeat");function ut(a,f){return Oe(de(a,f,Vi),a+"")}i(ut,"baseRest");function zg(a){return ah(Ad(a))}i(zg,"baseSample");function Ug(a,f){var m=Ad(a);return pr(m,Ts(f,0,m.length))}i(Ug,"baseSampleSize");function fu(a,f,m,x){if(!_r(a))return a;f=fa(f,a);for(var T=-1,P=f.length,H=P-1,$=a;$!=null&&++TT?0:T+f),m=m>T?T:m,m<0&&(m+=T),T=f>m?0:m-f>>>0,f>>>=0;for(var P=J(T);++x>>1,H=a[P];H!==null&&!_o(H)&&(m?H<=f:H=n){var le=f?null:Dw(a);if(le)return w(le);H=!1,T=co,X=new ia}else X=f?[]:$;e:for(;++x=x?a:Br(a,f,m)}i(ks,"castSlice");var Vg=Zp||function(a){return Rt.clearTimeout(a)};function Sh(a,f){if(f)return a.slice();var m=a.length,x=Qp?Qp(m):new a.constructor(m);return a.copy(x),x}i(Sh,"cloneBuffer");function du(a){var f=new a.constructor(a.byteLength);return new id(f).set(new id(a)),f}i(du,"cloneArrayBuffer");function Pw(a,f){var m=f?du(a.buffer):a.buffer;return new a.constructor(m,a.byteOffset,a.byteLength)}i(Pw,"cloneDataView");function Lw(a){var f=new a.constructor(a.source,Vf.exec(a));return f.lastIndex=a.lastIndex,f}i(Lw,"cloneRegExp");function Vc(a){return Mc?Ht(Mc.call(a)):{}}i(Vc,"cloneSymbol");function xh(a,f){var m=f?du(a.buffer):a.buffer;return new a.constructor(m,a.byteOffset,a.length)}i(xh,"cloneTypedArray");function Ch(a,f){if(a!==f){var m=a!==e,x=a===null,T=a===a,P=_o(a),H=f!==e,$=f===null,X=f===f,le=_o(f);if(!$&&!le&&!P&&a>f||P&&H&&X&&!$&&!le||x&&H&&X||!m&&X||!T)return 1;if(!x&&!P&&!le&&a=$)return X;var le=m[x];return X*(le=="desc"?-1:1)}}return a.index-f.index}i(Mw,"compareMultiple");function wd(a,f,m,x){for(var T=-1,P=a.length,H=m.length,$=-1,X=f.length,le=er(P-H,0),ue=J(X+le),fe=!x;++$1?m[T-1]:e,H=T>2?m[2]:e;for(P=a.length>3&&typeof P=="function"?(T--,P):e,H&&u(m[0],m[1],H)&&(P=T<3?e:P,T=1),f=Ht(f);++x-1?T[P?f[H]:H]:e}}i(Eh,"createFind");function Yg(a){return Qo(function(f){var m=f.length,x=m,T=Lt.prototype.thru;for(a&&f.reverse();x--;){var P=f[x];if(typeof P!="function")throw new Bi(l);if(T&&!H&&Xc(P)=="wrapper")var H=new Lt([],!0)}for(x=H?x:m;++x1&&St.reverse(),ue&&X$))return!1;var le=P.get(a),ue=P.get(f);if(le&&ue)return le==f&&ue==a;var fe=-1,Ne=!0,He=m&z?new ia:e;for(P.set(a,f),P.set(f,a);++fe<$;){var Ke=a[fe],dt=f[fe];if(x)var Ge=H?x(dt,Ke,fe,f,a,P):x(Ke,dt,fe,a,f,P);if(Ge!==e){if(Ge)continue;Ne=!1;break}if(He){if(!Qs(f,function(ht,St){if(!co(He,St)&&(Ke===ht||T(Ke,ht,m,x,P)))return He.push(St)})){Ne=!1;break}}else if(!(Ke===dt||T(Ke,dt,m,x,P))){Ne=!1;break}}return P.delete(a),P.delete(f),Ne}i(Ui,"equalArrays");function Ed(a,f,m,x,T,P,H){switch(m){case Yr:if(a.byteLength!=f.byteLength||a.byteOffset!=f.byteOffset)return!1;a=a.buffer,f=f.buffer;case Gr:return!(a.byteLength!=f.byteLength||!P(new id(a),new id(f)));case Gt:case Ft:case Fe:return Ns(+a,+f);case Ue:return a.name==f.name&&a.message==f.message;case lt:case fr:return a==f+"";case st:var $=Kl;case wr:var X=x&I;if($||($=w),a.size!=f.size&&!X)return!1;var le=H.get(a);if(le)return le==f;x|=z,H.set(a,f);var ue=Ui($(a),$(f),x,T,P,H);return H.delete(a),ue;case pt:if(Mc)return Mc.call(a)==Mc.call(f)}return!1}i(Ed,"equalByTag");function kh(a,f,m,x,T,P){var H=m&I,$=bd(a),X=$.length,le=bd(f),ue=le.length;if(X!=ue&&!H)return!1;for(var fe=X;fe--;){var Ne=$[fe];if(!(H?Ne in f:kt.call(f,Ne)))return!1}var He=P.get(a),Ke=P.get(f);if(He&&Ke)return He==f&&Ke==a;var dt=!0;P.set(a,f),P.set(f,a);for(var Ge=H;++fe1?"& ":"")+f[x],f=f.join(m>2?", ":" "),a.replace($f,`{ /* [wrapped with `+f+`] */ -`)}o(g,"insertWrapDetails");function y(s){return ot(s)||pf(s)||!!(pl&&s&&s[pl])}o(y,"isFlattenable");function S(s,f){var m=typeof s;return f=f??Ge,!!f&&(m=="number"||m!="symbol"&&$l.test(s))&&s>-1&&s%1==0&&s0){if(++f>=Ve)return arguments[0]}else f=0;return s.apply(e,arguments)}}o(dr,"shortOut");function Vr(s,f){var m=-1,x=s.length,_=x-1;for(f=f===e?x:f;++m1?s[f-1]:e;return m=typeof m=="function"?(s.pop(),m):e,ub(s,m)});function fb(s){var f=N(s);return f.__chain__=!0,f}o(fb,"chain");function eM(s,f){return f(s),s}o(eM,"tap");function Tg(s,f){return f(s)}o(Tg,"thru");var tM=ts(function(s){var f=s.length,m=f?s[0]:0,x=this.__wrapped__,_=o(function(L){return Nd(L,s)},"interceptor");return f>1||this.__actions__.length||!(x instanceof dt)||!S(m)?this.thru(_):(x=x.slice(m,+m+(f?1:0)),x.__actions__.push({func:Tg,args:[_],thisArg:e}),new An(x,this.__chain__).thru(function(L){return f&&!L.length&&L.push(e),L}))});function rM(){return fb(this)}o(rM,"wrapperChain");function nM(){return new An(this.value(),this.__chain__)}o(nM,"wrapperCommit");function iM(){this.__values__===e&&(this.__values__=Eb(this.value()));var s=this.__index__>=this.__values__.length,f=s?e:this.__values__[this.__index__++];return{done:s,value:f}}o(iM,"wrapperNext");function oM(){return this}o(oM,"wrapperToIterator");function sM(s){for(var f,m=this;m instanceof vc;){var x=bn(m);x.__index__=0,x.__values__=e,f?_.__wrapped__=x:f=x;var _=x;m=m.__wrapped__}return _.__wrapped__=s,f}o(sM,"wrapperPlant");function lM(){var s=this.__wrapped__;if(s instanceof dt){var f=s;return this.__actions__.length&&(f=new dt(this)),f=f.reverse(),f.__actions__.push({func:Tg,args:[sw],thisArg:e}),new An(f,this.__chain__)}return this.thru(sw)}o(lM,"wrapperReverse");function aM(){return ug(this.__wrapped__,this.__actions__)}o(aM,"wrapperValue");var uM=Ic(function(s,f,m){et.call(s,m)?++s[m]:yo(s,m,1)});function fM(s,f,m){var x=ot(s)?Mu:Cc;return m&&b(s,f,m)&&(f=e),x(s,Be(f,3))}o(fM,"every");function cM(s,f){var m=ot(s)?Vt:Pd;return m(s,Be(f,3))}o(cM,"filter");var pM=$d(zc),dM=$d(ob);function hM(s,f){return rn(kg(s,f),1)}o(hM,"flatMap");function mM(s,f){return rn(kg(s,f),Ke)}o(mM,"flatMapDeep");function gM(s,f,m){return m=m===e?1:lt(m),rn(kg(s,f),m)}o(gM,"flatMapDepth");function cb(s,f){var m=ot(s)?jn:di;return m(s,Be(f,3))}o(cb,"forEach");function pb(s,f){var m=ot(s)?dd:Sc;return m(s,Be(f,3))}o(pb,"forEachRight");var vM=Ic(function(s,f,m){et.call(s,m)?s[m].push(f):yo(s,m,[f])});function yM(s,f,m,x){s=Mi(s)?s:jc(s),m=m&&!x?lt(m):0;var _=s.length;return m<0&&(m=sr(_+m,0)),Mg(s)?m<=_&&s.indexOf(f,m)>-1:!!_&&Go(s,f,m)>-1}o(yM,"includes");var wM=st(function(s,f,m){var x=-1,_=typeof f=="function",L=Mi(s)?Q(s.length):[];return di(s,function(F){L[++x]=_?Ur(f,F,m):wa(F,f,m)}),L}),xM=Ic(function(s,f,m){yo(s,m,f)});function kg(s,f){var m=ot(s)?yt:Ea;return m(s,Be(f,3))}o(kg,"map");function SM(s,f,m,x){return s==null?[]:(ot(f)||(f=f==null?[]:[f]),m=x?e:m,ot(m)||(m=m==null?[]:[m]),yn(s,f,m))}o(SM,"orderBy");var CM=Ic(function(s,f,m){s[m?0:1].push(f)},function(){return[[],[]]});function bM(s,f,m){var x=ot(s)?Au:Fu,_=arguments.length<3;return x(s,Be(f,4),m,_,di)}o(bM,"reduce");function EM(s,f,m){var x=ot(s)?hd:Fu,_=arguments.length<3;return x(s,Be(f,4),m,_,Sc)}o(EM,"reduceRight");function _M(s,f){var m=ot(s)?Vt:Pd;return m(s,Pg(Be(f,3)))}o(_M,"reject");function TM(s){var f=ot(s)?wc:ew;return f(s)}o(TM,"sample");function kM(s,f,m){(m?b(s,f,m):f===e)?f=1:f=lt(f);var x=ot(s)?As:Fs;return x(s,f)}o(kM,"sampleSize");function NM(s){var f=ot(s)?Gm:Jo;return f(s)}o(NM,"shuffle");function LM(s){if(s==null)return 0;if(Mi(s))return Mg(s)?wr(s):s.length;var f=xn(s);return f==Yt||f==Jt?s.size:Nc(s).length}o(LM,"size");function PM(s,f,m){var x=ot(s)?Vo:tw;return m&&b(s,f,m)&&(f=e),x(s,Be(f,3))}o(PM,"some");var OM=st(function(s,f){if(s==null)return[];var m=f.length;return m>1&&b(s,f[0],f[1])?f=[]:m>2&&b(f[0],f[1],f[2])&&(f=[f[0]]),yn(s,rn(f,1),[])}),Ng=Fy||function(){return qt.Date.now()};function MM(s,f){if(typeof f!="function")throw new Kn(d);return s=lt(s),function(){if(--s<1)return f.apply(this,arguments)}}o(MM,"after");function db(s,f,m){return f=m?e:f,f=s&&f==null?s.length:f,Oi(s,se,e,e,e,e,f)}o(db,"ary");function hb(s,f){var m;if(typeof f!="function")throw new Kn(d);return s=lt(s),function(){return--s>0&&(m=f.apply(this,arguments)),s<=1&&(f=e),m}}o(hb,"before");var aw=st(function(s,f,m){var x=J;if(m.length){var _=Vi(m,Oa(aw));x|=G}return Oi(s,x,f,m,_)}),mb=st(function(s,f,m){var x=J|Z;if(m.length){var _=Vi(m,Oa(mb));x|=G}return Oi(f,x,s,m,_)});function gb(s,f,m){f=m?e:f;var x=Oi(s,A,e,e,e,e,e,f);return x.placeholder=gb.placeholder,x}o(gb,"curry");function vb(s,f,m){f=m?e:f;var x=Oi(s,I,e,e,e,e,e,f);return x.placeholder=vb.placeholder,x}o(vb,"curryRight");function yb(s,f,m){var x,_,L,F,z,Y,le=0,ae=!1,ce=!1,Le=!0;if(typeof s!="function")throw new Kn(d);f=So(f)||0,Sr(m)&&(ae=!!m.leading,ce="maxWait"in m,L=ce?sr(So(m.maxWait)||0,f):L,Le="trailing"in m?!!m.trailing:Le);function Fe(Ir){var is=x,kl=_;return x=_=e,le=Ir,F=s.apply(kl,is),F}o(Fe,"invokeFunc");function $e(Ir){return le=Ir,z=At(ht,f),ae?Fe(Ir):F}o($e,"leadingEdge");function ft(Ir){var is=Ir-Y,kl=Ir-le,Fb=f-is;return ce?Zr(Fb,L-kl):Fb}o(ft,"remainingWait");function je(Ir){var is=Ir-Y,kl=Ir-le;return Y===e||is>=f||is<0||ce&&kl>=L}o(je,"shouldInvoke");function ht(){var Ir=Ng();if(je(Ir))return gt(Ir);z=At(ht,ft(Ir))}o(ht,"timerExpired");function gt(Ir){return z=e,Le&&x?Fe(Ir):(x=_=e,F)}o(gt,"trailingEdge");function Xi(){z!==e&&Ta(z),le=0,x=Y=_=z=e}o(Xi,"cancel");function gi(){return z===e?F:gt(Ng())}o(gi,"flush");function Qi(){var Ir=Ng(),is=je(Ir);if(x=arguments,_=this,Y=Ir,is){if(z===e)return $e(Y);if(ce)return Ta(z),z=At(ht,f),Fe(Y)}return z===e&&(z=At(ht,f)),F}return o(Qi,"debounced"),Qi.cancel=Xi,Qi.flush=gi,Qi}o(yb,"debounce");var AM=st(function(s,f){return Qm(s,1,f)}),DM=st(function(s,f,m){return Qm(s,So(f)||0,m)});function RM(s){return Oi(s,pe)}o(RM,"flip");function Lg(s,f){if(typeof s!="function"||f!=null&&typeof f!="function")throw new Kn(d);var m=o(function(){var x=arguments,_=f?f.apply(this,x):x[0],L=m.cache;if(L.has(_))return L.get(_);var F=s.apply(this,x);return m.cache=L.set(_,F)||L,F},"memoized");return m.cache=new(Lg.Cache||xr),m}o(Lg,"memoize"),Lg.Cache=xr;function Pg(s){if(typeof s!="function")throw new Kn(d);return function(){var f=arguments;switch(f.length){case 0:return!s.call(this);case 1:return!s.call(this,f[0]);case 2:return!s.call(this,f[0],f[1]);case 3:return!s.call(this,f[0],f[1],f[2])}return!s.apply(this,f)}}o(Pg,"negate");function IM(s){return hb(2,s)}o(IM,"once");var FM=rw(function(s,f){f=f.length==1&&ot(f[0])?yt(f[0],zr(Be())):yt(rn(f,1),zr(Be()));var m=f.length;return st(function(x){for(var _=-1,L=Zr(x.length,m);++_=f}),pf=xa(function(){return arguments}())?xa:function(s){return Er(s)&&et.call(s,"callee")&&!hc.call(s,"callee")},ot=Q.isArray,ZM=ta?zr(ta):Qy;function Mi(s){return s!=null&&Og(s.length)&&!_l(s)}o(Mi,"isArrayLike");function Rr(s){return Er(s)&&Mi(s)}o(Rr,"isArrayLikeObject");function JM(s){return s===!0||s===!1||Er(s)&&jr(s)==zt}o(JM,"isBoolean");var Ra=qu||xw,eA=Ou?zr(Ou):Sa;function tA(s){return Er(s)&&s.nodeType===1&&!Gd(s)}o(tA,"isElement");function rA(s){if(s==null)return!0;if(Mi(s)&&(ot(s)||typeof s=="string"||typeof s.splice=="function"||Ra(s)||$c(s)||pf(s)))return!s.length;var f=xn(s);if(f==Yt||f==Jt)return!s.size;if(te(s))return!Nc(s).length;for(var m in s)if(et.call(s,m))return!1;return!0}o(rA,"isEmpty");function nA(s,f){return Ca(s,f)}o(nA,"isEqual");function iA(s,f,m){m=typeof m=="function"?m:e;var x=m?m(s,f):e;return x===e?Ca(s,f,e,m):!!x}o(iA,"isEqualWith");function fw(s){if(!Er(s))return!1;var f=jr(s);return f==rt||f==ie||typeof s.message=="string"&&typeof s.name=="string"&&!Gd(s)}o(fw,"isError");function oA(s){return typeof s=="number"&&Um(s)}o(oA,"isFinite");function _l(s){if(!Sr(s))return!1;var f=jr(s);return f==Pr||f==Gt||f==Lr||f==si}o(_l,"isFunction");function xb(s){return typeof s=="number"&&s==lt(s)}o(xb,"isInteger");function Og(s){return typeof s=="number"&&s>-1&&s%1==0&&s<=Ge}o(Og,"isLength");function Sr(s){var f=typeof s;return s!=null&&(f=="object"||f=="function")}o(Sr,"isObject");function Er(s){return s!=null&&typeof s=="object"}o(Er,"isObjectLike");var Sb=nt?zr(nt):tg;function sA(s,f){return s===f||wl(s,f,Ma(f))}o(sA,"isMatch");function lA(s,f,m){return m=typeof m=="function"?m:e,wl(s,f,Ma(f),m)}o(lA,"isMatchWith");function aA(s){return Cb(s)&&s!=+s}o(aA,"isNaN");function uA(s){if($(s))throw new Qe(l);return ba(s)}o(uA,"isNative");function fA(s){return s===null}o(fA,"isNull");function cA(s){return s==null}o(cA,"isNil");function Cb(s){return typeof s=="number"||Er(s)&&jr(s)==Se}o(Cb,"isNumber");function Gd(s){if(!Er(s)||jr(s)!=fn)return!1;var f=ca(s);if(f===null)return!0;var m=et.call(f,"constructor")&&f.constructor;return typeof m=="function"&&m instanceof m&&ho.call(m)==Ry}o(Gd,"isPlainObject");var cw=uc?zr(uc):ef;function pA(s){return xb(s)&&s>=-Ge&&s<=Ge}o(pA,"isSafeInteger");var bb=fi?zr(fi):tf;function Mg(s){return typeof s=="string"||!ot(s)&&Er(s)&&jr(s)==gr}o(Mg,"isString");function Yi(s){return typeof s=="symbol"||Er(s)&&jr(s)==pt}o(Yi,"isSymbol");var $c=ll?zr(ll):rg;function dA(s){return s===e}o(dA,"isUndefined");function hA(s){return Er(s)&&xn(s)==Cr}o(hA,"isWeakMap");function mA(s){return Er(s)&&jr(s)==Ui}o(mA,"isWeakSet");var gA=Mt(Is),vA=Mt(function(s,f){return s<=f});function Eb(s){if(!s)return[];if(Mi(s))return Mg(s)?Kt(s):qr(s);if(_s&&s[_s])return pc(s[_s]());var f=xn(s),m=f==Yt?aa:f==Jt?w:jc;return m(s)}o(Eb,"toArray");function Tl(s){if(!s)return s===0?s:0;if(s=So(s),s===Ke||s===-Ke){var f=s<0?-1:1;return f*Xe}return s===s?s:0}o(Tl,"toFinite");function lt(s){var f=Tl(s),m=f%1;return f===f?m?f-m:f:0}o(lt,"toInteger");function _b(s){return s?vl(lt(s),0,ct):0}o(_b,"toLength");function So(s){if(typeof s=="number")return s;if(Yi(s))return nr;if(Sr(s)){var f=typeof s.valueOf=="function"?s.valueOf():s;s=Sr(f)?f+"":f}if(typeof s!="string")return s===0?s:+s;s=Ss(s);var m=Wo.test(s);return m||Uo.test(s)?ye(s.slice(2),m?2:8):xu.test(s)?nr:+s}o(So,"toNumber");function Tb(s){return Gn(s,Ai(s))}o(Tb,"toPlainObject");function yA(s){return s?vl(lt(s),-Ge,Ge):s===0?s:0}o(yA,"toSafeInteger");function Dt(s){return s==null?"":wn(s)}o(Dt,"toString");var wA=ka(function(s,f){if(te(f)||Mi(f)){Gn(f,_n(f),s);return}for(var m in f)et.call(f,m)&&Qu(s,m,f[m])}),kb=ka(function(s,f){Gn(f,Ai(f),s)}),Ag=ka(function(s,f,m,x){Gn(f,Ai(f),s,x)}),xA=ka(function(s,f,m,x){Gn(f,_n(f),s,x)}),SA=ts(Nd);function CA(s,f){var m=go(s);return f==null?m:kd(m,f)}o(CA,"create");var bA=st(function(s,f){s=mt(s);var m=-1,x=f.length,_=x>2?f[2]:e;for(_&&b(f[0],f[1],_)&&(x=1);++m1),L}),Gn(s,Hc(s),m),x&&(m=Dn(m,k|O|j,Cg));for(var _=f.length;_--;)of(m,f[_]);return m});function UA(s,f){return Lb(s,Pg(Be(f)))}o(UA,"omitBy");var zA=ts(function(s,f){return s==null?{}:sg(s,f)});function Lb(s,f){if(s==null)return{};var m=yt(Hc(s),function(x){return[x]});return f=Be(f),lg(s,m,function(x,_){return f(x,_[0])})}o(Lb,"pickBy");function $A(s,f,m){f=Gi(f,s);var x=-1,_=f.length;for(_||(_=1,s=e);++x<_;){var L=s==null?e:s[Lt(f[x])];L===e&&(x=_,L=m),s=_l(L)?L.call(s):L}return s}o($A,"result");function jA(s,f,m){return s==null?s:Zo(s,f,m)}o(jA,"set");function qA(s,f,m,x){return x=typeof x=="function"?x:e,s==null?s:Zo(s,f,m,x)}o(qA,"setWith");var Pb=Pi(_n),Ob=Pi(Ai);function VA(s,f,m){var x=ot(s),_=x||Ra(s)||$c(s);if(f=Be(f,4),m==null){var L=s&&s.constructor;_?m=x?new L:[]:Sr(s)?m=_l(L)?go(ca(s)):{}:m={}}return(_?jn:hi)(s,function(F,z,Y){return f(m,F,z,Y)}),m}o(VA,"transform");function KA(s,f){return s==null?!0:of(s,f)}o(KA,"unset");function GA(s,f,m){return s==null?s:Mc(s,f,Ac(m))}o(GA,"update");function YA(s,f,m,x){return x=typeof x=="function"?x:e,s==null?s:Mc(s,f,Ac(m),x)}o(YA,"updateWith");function jc(s){return s==null?[]:sa(s,_n(s))}o(jc,"values");function XA(s){return s==null?[]:sa(s,Ai(s))}o(XA,"valuesIn");function QA(s,f,m){return m===e&&(m=f,f=e),m!==e&&(m=So(m),m=m===m?m:0),f!==e&&(f=So(f),f=f===f?f:0),vl(So(s),f,m)}o(QA,"clamp");function ZA(s,f,m){return f=Tl(f),m===e?(m=f,f=0):m=Tl(m),s=So(s),ya(s,f,m)}o(ZA,"inRange");function JA(s,f,m){if(m&&typeof m!="boolean"&&b(s,f,m)&&(f=m=e),m===e&&(typeof f=="boolean"?(m=f,f=e):typeof s=="boolean"&&(m=s,s=e)),s===e&&f===e?(s=0,f=1):(s=Tl(s),f===e?(f=s,s=0):f=Tl(f)),s>f){var x=s;s=f,f=x}if(m||s%1||f%1){var _=Ns();return Zr(s+_*(f-s+Pu("1e-"+((_+"").length-1))),f)}return Pc(s,f)}o(JA,"random");var e2=Na(function(s,f,m){return f=f.toLowerCase(),s+(m?Mb(f):f)});function Mb(s){return hw(Dt(s).toLowerCase())}o(Mb,"capitalize");function Ab(s){return s=Dt(s),s&&s.replace(ec,Wu).replace(sc,"")}o(Ab,"deburr");function t2(s,f,m){s=Dt(s),f=wn(f);var x=s.length;m=m===e?x:vl(lt(m),0,x);var _=m;return m-=f.length,m>=0&&s.slice(m,_)==f}o(t2,"endsWith");function r2(s){return s=Dt(s),s&&ds.test(s)?s.replace(or,gd):s}o(r2,"escape");function n2(s){return s=Dt(s),s&&Qf.test(s)?s.replace(tl,"\\$&"):s}o(n2,"escapeRegExp");var i2=Na(function(s,f,m){return s+(m?"-":"")+f.toLowerCase()}),o2=Na(function(s,f,m){return s+(m?" ":"")+f.toLowerCase()}),s2=yg("toLowerCase");function l2(s,f,m){s=Dt(s),f=lt(f);var x=f?wr(s):0;if(!f||x>=f)return s;var _=(f-x)/2;return Fc(ha(_),m)+s+Fc(da(_),m)}o(l2,"pad");function a2(s,f,m){s=Dt(s),f=lt(f);var x=f?wr(s):0;return f&&x>>0,m?(s=Dt(s),s&&(typeof f=="string"||f!=null&&!cw(f))&&(f=wn(f),!f&&qn(s))?Bs(Kt(s),0,m):s.split(f,m)):[]}o(h2,"split");var m2=Na(function(s,f,m){return s+(m?" ":"")+hw(f)});function g2(s,f,m){return s=Dt(s),m=m==null?0:vl(lt(m),0,s.length),f=wn(f),s.slice(m,m+f.length)==f}o(g2,"startsWith");function v2(s,f,m){var x=N.templateSettings;m&&b(s,f,m)&&(f=e),s=Dt(s),f=Ag({},f,x,Bc);var _=Ag({},f.imports,x.imports,Bc),L=_n(_),F=sa(_,L),z,Y,le=0,ae=f.interpolate||jt,ce="__p += '",Le=Cs((f.escape||jt).source+"|"+ae.source+"|"+(ae===el?Jf:jt).source+"|"+(f.evaluate||jt).source+"|$","g"),Fe="//# sourceURL="+(et.call(f,"sourceURL")?(f.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++Lu+"]")+` -`;s.replace(Le,function(je,ht,gt,Xi,gi,Qi){return gt||(gt=Xi),ce+=s.slice(le,Qi).replace(Me,Uu),ht&&(z=!0,ce+=`' + +`)}i(r,"insertWrapDetails");function o(a){return at(a)||Jc(a)||!!(mg&&a&&a[mg])}i(o,"isFlattenable");function c(a,f){var m=typeof a;return f=f??Qe,!!f&&(m=="number"||m!="symbol"&&La.test(a))&&a>-1&&a%1==0&&a0){if(++f>=Ee)return arguments[0]}else f=0;return a.apply(e,arguments)}}i(Dt,"shortOut");function pr(a,f){var m=-1,x=a.length,T=x-1;for(f=f===e?x:f;++m1?a[f-1]:e;return m=typeof m=="function"?(a.pop(),m):e,jE(a,m)});function KE(a){var f=A(a);return f.__chain__=!0,f}i(KE,"chain");function wR(a,f){return f(a),a}i(wR,"tap");function rv(a,f){return f(a)}i(rv,"thru");var SR=Qo(function(a){var f=a.length,m=f?a[0]:0,x=this.__wrapped__,T=i(function(P){return ru(P,a)},"interceptor");return f>1||this.__actions__.length||!(x instanceof $e)||!c(m)?this.thru(T):(x=x.slice(m,+m+(f?1:0)),x.__actions__.push({func:rv,args:[T],thisArg:e}),new Lt(x,this.__chain__).thru(function(P){return f&&!P.length&&P.push(e),P}))});function xR(){return KE(this)}i(xR,"wrapperChain");function CR(){return new Lt(this.value(),this.__chain__)}i(CR,"wrapperCommit");function _R(){this.__values__===e&&(this.__values__=ab(this.value()));var a=this.__index__>=this.__values__.length,f=a?e:this.__values__[this.__index__++];return{done:a,value:f}}i(_R,"wrapperNext");function ER(){return this}i(ER,"wrapperToIterator");function bR(a){for(var f,m=this;m instanceof vn;){var x=Nn(m);x.__index__=0,x.__values__=e,f?T.__wrapped__=x:f=x;var T=x;m=m.__wrapped__}return T.__wrapped__=a,f}i(bR,"wrapperPlant");function TR(){var a=this.__wrapped__;if(a instanceof $e){var f=a;return this.__actions__.length&&(f=new $e(this)),f=f.reverse(),f.__actions__.push({func:rv,args:[Hw],thisArg:e}),new Lt(f,this.__chain__)}return this.thru(Hw)}i(TR,"wrapperReverse");function kR(){return zc(this.__wrapped__,this.__actions__)}i(kR,"wrapperValue");var NR=pu(function(a,f,m){kt.call(a,m)?++a[m]:bs(a,m,1)});function AR(a,f,m){var x=at(a)?wc:bw;return m&&u(a,f,m)&&(f=e),x(a,We(f,3))}i(AR,"every");function PR(a,f){var m=at(a)?jt:Xa;return m(a,We(f,3))}i(PR,"filter");var LR=Eh(Zo),MR=Eh(ma);function OR(a,f){return Fr(nv(a,f),1)}i(OR,"flatMap");function RR(a,f){return Fr(nv(a,f),je)}i(RR,"flatMapDeep");function DR(a,f,m){return m=m===e?1:ct(m),Fr(nv(a,f),m)}i(DR,"flatMapDepth");function GE(a,f){var m=at(a)?Zn:So;return m(a,We(f,3))}i(GE,"forEach");function YE(a,f){var m=at(a)?Xf:fh;return m(a,We(f,3))}i(YE,"forEachRight");var IR=pu(function(a,f,m){kt.call(a,m)?a[m].push(f):bs(a,m,[f])});function FR(a,f,m,x){a=Wi(a)?a:Ad(a),m=m&&!x?ct(m):0;var T=a.length;return m<0&&(m=er(T+m,0)),lv(a)?m<=T&&a.indexOf(f,m)>-1:!!T&&Kt(a,f,m)>-1}i(FR,"includes");var BR=ut(function(a,f,m){var x=-1,T=typeof f=="function",P=Wi(a)?J(a.length):[];return So(a,function(H){P[++x]=T?Qr(f,H,m):su(H,f,m)}),P}),HR=pu(function(a,f,m){bs(a,m,f)});function nv(a,f){var m=at(a)?$t:mh;return m(a,We(f,3))}i(nv,"map");function zR(a,f,m,x){return a==null?[]:(at(f)||(f=f==null?[]:[f]),m=x?e:m,at(m)||(m=m==null?[]:[m]),Fg(a,f,m))}i(zR,"orderBy");var UR=pu(function(a,f,m){a[m?0:1].push(f)},function(){return[[],[]]});function WR(a,f,m){var x=at(a)?Sc:ed,T=arguments.length<3;return x(a,We(f,4),m,T,So)}i(WR,"reduce");function $R(a,f,m){var x=at(a)?Qf:ed,T=arguments.length<3;return x(a,We(f,4),m,T,fh)}i($R,"reduceRight");function VR(a,f){var m=at(a)?jt:Xa;return m(a,sv(We(f,3)))}i(VR,"reject");function qR(a){var f=at(a)?ah:zg;return f(a)}i(qR,"sample");function jR(a,f,m){(m?u(a,f,m):f===e)?f=1:f=ct(f);var x=at(a)?_w:Ug;return x(a,f)}i(jR,"sampleSize");function KR(a){var f=at(a)?lh:Aw;return f(a)}i(KR,"shuffle");function GR(a){if(a==null)return 0;if(Wi(a))return lv(a)?mn(a):a.length;var f=Hr(a);return f==st||f==wr?a.size:Ja(a).length}i(GR,"size");function YR(a,f,m){var x=at(a)?Qs:Bc;return m&&u(a,f,m)&&(f=e),x(a,We(f,3))}i(YR,"some");var XR=ut(function(a,f){if(a==null)return[];var m=f.length;return m>1&&u(a,f[0],f[1])?f=[]:m>2&&u(f[0],f[1],f[2])&&(f=[f[0]]),Fg(a,Fr(f,1),[])}),iv=Jl||function(){return Rt.Date.now()};function QR(a,f){if(typeof f!="function")throw new Bi(l);return a=ct(a),function(){if(--a<1)return f.apply(this,arguments)}}i(QR,"after");function XE(a,f,m){return f=m?e:f,f=a&&f==null?a.length:f,wt(a,re,e,e,e,e,f)}i(XE,"ary");function QE(a,f){var m;if(typeof f!="function")throw new Bi(l);return a=ct(a),function(){return--a>0&&(m=f.apply(this,arguments)),a<=1&&(f=e),m}}i(QE,"before");var Uw=ut(function(a,f,m){var x=q;if(m.length){var T=Tn(m,vu(Uw));x|=B}return wt(a,x,f,m,T)}),JE=ut(function(a,f,m){var x=q|Q;if(m.length){var T=Tn(m,vu(JE));x|=B}return wt(f,x,a,m,T)});function ZE(a,f,m){f=m?e:f;var x=wt(a,D,e,e,e,e,e,f);return x.placeholder=ZE.placeholder,x}i(ZE,"curry");function eb(a,f,m){f=m?e:f;var x=wt(a,L,e,e,e,e,e,f);return x.placeholder=eb.placeholder,x}i(eb,"curryRight");function tb(a,f,m){var x,T,P,H,$,X,le=0,ue=!1,fe=!1,Ne=!0;if(typeof a!="function")throw new Bi(l);f=ts(f)||0,_r(m)&&(ue=!!m.leading,fe="maxWait"in m,P=fe?er(ts(m.maxWait)||0,f):P,Ne="trailing"in m?!!m.trailing:Ne);function He(Wr){var As=x,ol=T;return x=T=e,le=Wr,H=a.apply(ol,As),H}i(He,"invokeFunc");function Ke(Wr){return le=Wr,$=Ie(ht,f),ue?He(Wr):H}i(Ke,"leadingEdge");function dt(Wr){var As=Wr-X,ol=Wr-le,Sb=f-As;return fe?Ar(Sb,P-ol):Sb}i(dt,"remainingWait");function Ge(Wr){var As=Wr-X,ol=Wr-le;return X===e||As>=f||As<0||fe&&ol>=P}i(Ge,"shouldInvoke");function ht(){var Wr=iv();if(Ge(Wr))return St(Wr);$=Ie(ht,dt(Wr))}i(ht,"timerExpired");function St(Wr){return $=e,Ne&&x?He(Wr):(x=T=e,H)}i(St,"trailingEdge");function Eo(){$!==e&&Vg($),le=0,x=X=T=$=e}i(Eo,"cancel");function Ci(){return $===e?H:St(iv())}i(Ci,"flush");function bo(){var Wr=iv(),As=Ge(Wr);if(x=arguments,T=this,X=Wr,As){if($===e)return Ke(X);if(fe)return Vg($),$=Ie(ht,f),He(X)}return $===e&&($=Ie(ht,f)),H}return i(bo,"debounced"),bo.cancel=Eo,bo.flush=Ci,bo}i(tb,"debounce");var JR=ut(function(a,f){return Tg(a,1,f)}),ZR=ut(function(a,f,m){return Tg(a,ts(f)||0,m)});function eD(a){return wt(a,oe)}i(eD,"flip");function ov(a,f){if(typeof a!="function"||f!=null&&typeof f!="function")throw new Bi(l);var m=i(function(){var x=arguments,T=f?f.apply(this,x):x[0],P=m.cache;if(P.has(T))return P.get(T);var H=a.apply(this,x);return m.cache=P.set(T,H)||P,H},"memoized");return m.cache=new(ov.Cache||yo),m}i(ov,"memoize"),ov.Cache=yo;function sv(a){if(typeof a!="function")throw new Bi(l);return function(){var f=arguments;switch(f.length){case 0:return!a.call(this);case 1:return!a.call(this,f[0]);case 2:return!a.call(this,f[0],f[1]);case 3:return!a.call(this,f[0],f[1],f[2])}return!a.apply(this,f)}}i(sv,"negate");function tD(a){return QE(2,a)}i(tD,"once");var rD=$c(function(a,f){f=f.length==1&&at(f[0])?$t(f[0],hn(We())):$t(Fr(f,1),hn(We()));var m=f.length;return ut(function(x){for(var T=-1,P=Ar(x.length,m);++T=f}),Jc=ph(function(){return arguments}())?ph:function(a){return Lr(a)&&kt.call(a,"callee")&&!od.call(a,"callee")},at=J.isArray,vD=Xs?hn(Xs):au;function Wi(a){return a!=null&&av(a.length)&&!nl(a)}i(Wi,"isArrayLike");function Ur(a){return Lr(a)&&Wi(a)}i(Ur,"isArrayLikeObject");function yD(a){return a===!0||a===!1||Lr(a)&&Zr(a)==Gt}i(yD,"isBoolean");var Su=dw||Zw,wD=vi?hn(vi):Lg;function SD(a){return Lr(a)&&a.nodeType===1&&!Ph(a)}i(SD,"isElement");function xD(a){if(a==null)return!0;if(Wi(a)&&(at(a)||typeof a=="string"||typeof a.splice=="function"||Su(a)||Nd(a)||Jc(a)))return!a.length;var f=Hr(a);if(f==st||f==wr)return!a.size;if(E(a))return!Ja(a).length;for(var m in a)if(kt.call(a,m))return!1;return!0}i(xD,"isEmpty");function CD(a,f){return ua(a,f)}i(CD,"isEqual");function _D(a,f,m){m=typeof m=="function"?m:e;var x=m?m(a,f):e;return x===e?ua(a,f,e,m):!!x}i(_D,"isEqualWith");function $w(a){if(!Lr(a))return!1;var f=Zr(a);return f==Ue||f==se||typeof a.message=="string"&&typeof a.name=="string"&&!Ph(a)}i($w,"isError");function ED(a){return typeof a=="number"&&gg(a)}i(ED,"isFinite");function nl(a){if(!_r(a))return!1;var f=Zr(a);return f==Kr||f==Zt||f==yr||f==Ho}i(nl,"isFunction");function nb(a){return typeof a=="number"&&a==ct(a)}i(nb,"isInteger");function av(a){return typeof a=="number"&&a>-1&&a%1==0&&a<=Qe}i(av,"isLength");function _r(a){var f=typeof a;return a!=null&&(f=="object"||f=="function")}i(_r,"isObject");function Lr(a){return a!=null&&typeof a=="object"}i(Lr,"isObjectLike");var ib=Ze?hn(Ze):Ic;function bD(a,f){return a===f||hh(a,f,bt(f))}i(bD,"isMatch");function TD(a,f,m){return m=typeof m=="function"?m:e,hh(a,f,bt(f),m)}i(TD,"isMatchWith");function kD(a){return ob(a)&&a!=+a}i(kD,"isNaN");function ND(a){if(_(a))throw new Je(s);return Qa(a)}i(ND,"isNative");function AD(a){return a===null}i(AD,"isNull");function PD(a){return a==null}i(PD,"isNil");function ob(a){return typeof a=="number"||Lr(a)&&Zr(a)==Fe}i(ob,"isNumber");function Ph(a){if(!Lr(a)||Zr(a)!=En)return!1;var f=ra(a);if(f===null)return!0;var m=kt.call(f,"constructor")&&f.constructor;return typeof m=="function"&&m instanceof m&&Xl.call(m)==Ua}i(Ph,"isPlainObject");var Vw=Bl?hn(Bl):Og;function LD(a){return nb(a)&&a>=-Qe&&a<=Qe}i(LD,"isSafeInteger");var sb=pn?hn(pn):Rg;function lv(a){return typeof a=="string"||!at(a)&&Lr(a)&&Zr(a)==fr}i(lv,"isString");function _o(a){return typeof a=="symbol"||Lr(a)&&Zr(a)==pt}i(_o,"isSymbol");var Nd=Hl?hn(Hl):Dg;function MD(a){return a===e}i(MD,"isUndefined");function OD(a){return Lr(a)&&Hr(a)==Bn}i(OD,"isWeakMap");function RD(a){return Lr(a)&&Zr(a)==Mi}i(RD,"isWeakSet");var DD=jc(Za),ID=jc(function(a,f){return a<=f});function ab(a){if(!a)return[];if(Wi(a))return lv(a)?Xt(a):ei(a);if($a&&a[$a])return Xp(a[$a]());var f=Hr(a),m=f==st?Kl:f==wr?w:Ad;return m(a)}i(ab,"toArray");function il(a){if(!a)return a===0?a:0;if(a=ts(a),a===je||a===-je){var f=a<0?-1:1;return f*ot}return a===a?a:0}i(il,"toFinite");function ct(a){var f=il(a),m=f%1;return f===f?m?f-m:f:0}i(ct,"toInteger");function lb(a){return a?Ts(ct(a),0,At):0}i(lb,"toLength");function ts(a){if(typeof a=="number")return a;if(_o(a))return It;if(_r(a)){var f=typeof a.valueOf=="function"?a.valueOf():a;a=_r(f)?f+"":f}if(typeof a!="string")return a===0?a:+a;a=Vl(a);var m=vs.test(a);return m||Up.test(a)?ve(a.slice(2),m?2:8):ac.test(a)?It:+a}i(ts,"toNumber");function ub(a){return Co(a,$i(a))}i(ub,"toPlainObject");function FD(a){return a?Ts(ct(a),-Qe,Qe):a===0?a:0}i(FD,"toSafeInteger");function zt(a){return a==null?"":Si(a)}i(zt,"toString");var BD=Xo(function(a,f){if(E(f)||Wi(f)){Co(f,Pn(f),a);return}for(var m in f)kt.call(f,m)&&eu(a,m,f[m])}),cb=Xo(function(a,f){Co(f,$i(f),a)}),uv=Xo(function(a,f,m,x){Co(f,$i(f),a,x)}),HD=Xo(function(a,f,m,x){Co(f,Pn(f),a,x)}),zD=Qo(ru);function UD(a,f){var m=Zl(a);return f==null?m:uh(m,f)}i(UD,"create");var WD=ut(function(a,f){a=Ht(a);var m=-1,x=f.length,T=x>2?f[2]:e;for(T&&u(f[0],f[1],T)&&(x=1);++m1),P}),Co(a,Td(a),m),x&&(m=wi(m,b|k|R,Gc));for(var T=f.length;T--;)vd(m,f[T]);return m});function s2(a,f){return db(a,sv(We(f)))}i(s2,"omitBy");var a2=Qo(function(a,f){return a==null?{}:Bg(a,f)});function db(a,f){if(a==null)return{};var m=$t(Td(a),function(x){return[x]});return f=We(f),Hg(a,m,function(x,T){return f(x,T[0])})}i(db,"pickBy");function l2(a,f,m){f=fa(f,a);var x=-1,T=f.length;for(T||(T=1,a=e);++xf){var x=a;a=f,f=x}if(m||a%1||f%1){var T=nh();return Ar(a+T*(f-a+Fl("1e-"+((T+"").length-1))),f)}return gd(a,f)}i(y2,"random");var w2=mu(function(a,f,m){return f=f.toLowerCase(),a+(m?mb(f):f)});function mb(a){return Kw(zt(a).toLowerCase())}i(mb,"capitalize");function gb(a){return a=zt(a),a&&a.replace(lc,Tc).replace($p,"")}i(gb,"deburr");function S2(a,f,m){a=zt(a),f=Si(f);var x=a.length;m=m===e?x:Ts(ct(m),0,x);var T=m;return m-=f.length,m>=0&&a.slice(m,T)==f}i(S2,"endsWith");function x2(a){return a=zt(a),a&&Na.test(a)?a.replace(Mt,Fi):a}i(x2,"escape");function C2(a){return a=zt(a),a&&nc.test(a)?a.replace(Pa,"\\$&"):a}i(C2,"escapeRegExp");var _2=mu(function(a,f,m){return a+(m?"-":"")+f.toLowerCase()}),E2=mu(function(a,f,m){return a+(m?" ":"")+f.toLowerCase()}),b2=Gg("toLowerCase");function T2(a,f,m){a=zt(a),f=ct(f);var x=f?mn(a):0;if(!f||x>=f)return a;var T=(f-x)/2;return Cd(Va(T),m)+a+Cd(Ac(T),m)}i(T2,"pad");function k2(a,f,m){a=zt(a),f=ct(f);var x=f?mn(a):0;return f&&x>>0,m?(a=zt(a),a&&(typeof f=="string"||f!=null&&!Vw(f))&&(f=Si(f),!f&&xs(a))?ks(Xt(a),0,m):a.split(f,m)):[]}i(O2,"split");var R2=mu(function(a,f,m){return a+(m?" ":"")+Kw(f)});function D2(a,f,m){return a=zt(a),m=m==null?0:Ts(ct(m),0,a.length),f=Si(f),a.slice(m,m+f.length)==f}i(D2,"startsWith");function I2(a,f,m){var x=A.templateSettings;m&&u(a,f,m)&&(f=e),a=zt(a),f=uv({},f,x,Jg);var T=uv({},f.imports,x.imports,Jg),P=Pn(T),H=bc(T,P),$,X,le=0,ue=f.interpolate||ao,fe="__p += '",Ne=Nc((f.escape||ao).source+"|"+ue.source+"|"+(ue===kr?Nl:ao).source+"|"+(f.evaluate||ao).source+"|$","g"),He="//# sourceURL="+(kt.call(f,"sourceURL")?(f.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++jp+"]")+` +`;a.replace(Ne,function(Ge,ht,St,Eo,Ci,bo){return St||(St=Eo),fe+=a.slice(le,bo).replace(qf,$o),ht&&($=!0,fe+=`' + __e(`+ht+`) + -'`),gi&&(Y=!0,ce+=`'; -`+gi+`; -__p += '`),gt&&(ce+=`' + -((__t = (`+gt+`)) == null ? '' : __t) + -'`),le=Qi+je.length,je}),ce+=`'; -`;var $e=et.call(f,"variable")&&f.variable;if(!$e)ce=`with (obj) { -`+ce+` +'`),Ci&&(X=!0,fe+=`'; +`+Ci+`; +__p += '`),St&&(fe+=`' + +((__t = (`+St+`)) == null ? '' : __t) + +'`),le=bo+Ge.length,Ge}),fe+=`'; +`;var Ke=kt.call(f,"variable")&&f.variable;if(!Ke)fe=`with (obj) { +`+fe+` } -`;else if(ms.test($e))throw new Qe(h);ce=(Y?ce.replace(ir,""):ce).replace(Ul,"$1").replace(Ft,"$1;"),ce="function("+($e||"obj")+`) { -`+($e?"":`obj || (obj = {}); -`)+"var __t, __p = ''"+(z?", __e = _.escape":"")+(Y?`, __j = Array.prototype.join; +`;else if(Bp.test(Ke))throw new Je(h);fe=(X?fe.replace(Tl,""):fe).replace(ze,"$1").replace(Xr,"$1;"),fe="function("+(Ke||"obj")+`) { +`+(Ke?"":`obj || (obj = {}); +`)+"var __t, __p = ''"+($?", __e = _.escape":"")+(X?`, __j = Array.prototype.join; function print() { __p += __j.call(arguments, '') } `:`; -`)+ce+`return __p -}`;var ft=Rb(function(){return bt(L,Fe+"return "+ce).apply(e,F)});if(ft.source=ce,fw(ft))throw ft;return ft}o(v2,"template");function y2(s){return Dt(s).toLowerCase()}o(y2,"toLower");function w2(s){return Dt(s).toUpperCase()}o(w2,"toUpper");function x2(s,f,m){if(s=Dt(s),s&&(m||f===e))return Ss(s);if(!s||!(f=wn(f)))return s;var x=Kt(s),_=Kt(f),L=qi(x,_),F=al(x,_)+1;return Bs(x,L,F).join("")}o(x2,"trim");function S2(s,f,m){if(s=Dt(s),s&&(m||f===e))return s.slice(0,gn(s)+1);if(!s||!(f=wn(f)))return s;var x=Kt(s),_=al(x,Kt(f))+1;return Bs(x,0,_).join("")}o(S2,"trimEnd");function C2(s,f,m){if(s=Dt(s),s&&(m||f===e))return s.replace(rl,"");if(!s||!(f=wn(f)))return s;var x=Kt(s),_=qi(x,Kt(f));return Bs(x,_).join("")}o(C2,"trimStart");function b2(s,f){var m=me,x=xe;if(Sr(f)){var _="separator"in f?f.separator:_;m="length"in f?lt(f.length):m,x="omission"in f?wn(f.omission):x}s=Dt(s);var L=s.length;if(qn(s)){var F=Kt(s);L=F.length}if(m>=L)return s;var z=m-wr(x);if(z<1)return x;var Y=F?Bs(F,0,z).join(""):s.slice(0,z);if(_===e)return Y+x;if(F&&(z+=Y.length-z),cw(_)){if(s.slice(z).search(_)){var le,ae=Y;for(_.global||(_=Cs(_.source,Dt(nl.exec(_))+"g")),_.lastIndex=0;le=_.exec(ae);)var ce=le.index;Y=Y.slice(0,ce===e?z:ce)}}else if(s.indexOf(wn(_),z)!=z){var Le=Y.lastIndexOf(_);Le>-1&&(Y=Y.slice(0,Le))}return Y+x}o(b2,"truncate");function E2(s){return s=Dt(s),s&&li.test(s)?s.replace(Wr,ci):s}o(E2,"unescape");var _2=Na(function(s,f,m){return s+(m?" ":"")+f.toUpperCase()}),hw=yg("toUpperCase");function Db(s,f,m){return s=Dt(s),f=m?e:f,f===e?Ti(s)?Vn(s):Du(s):s.match(f)||[]}o(Db,"words");var Rb=st(function(s,f){try{return Ur(s,e,f)}catch(m){return fw(m)?m:new Qe(m)}}),T2=ts(function(s,f){return jn(f,function(m){m=Lt(m),yo(s,m,aw(s[m],s))}),s});function k2(s){var f=s==null?0:s.length,m=Be();return s=f?yt(s,function(x){if(typeof x[1]!="function")throw new Kn(d);return[m(x[0]),x[1]]}):[],st(function(x){for(var _=-1;++_Ge)return[];var m=ct,x=Zr(s,ct);f=Be(f),s-=ct;for(var _=Yo(x,f);++m0||f<0)?new dt(m):(s<0?m=m.takeRight(-s):s&&(m=m.drop(s)),f!==e&&(f=lt(f),m=f<0?m.dropRight(-f):m.take(f-s)),m)},dt.prototype.takeRightWhile=function(s){return this.reverse().takeWhile(s).reverse()},dt.prototype.toArray=function(){return this.take(ct)},hi(dt.prototype,function(s,f){var m=/^(?:filter|find|map|reject)|While$/.test(f),x=/^(?:head|last)$/.test(f),_=N[x?"take"+(f=="last"?"Right":""):f],L=x||/^find/.test(f);!_||(N.prototype[f]=function(){var F=this.__wrapped__,z=x?[1]:arguments,Y=F instanceof dt,le=z[0],ae=Y||ot(F),ce=o(function(ht){var gt=_.apply(N,$i([ht],z));return x&&Le?gt[0]:gt},"interceptor");ae&&m&&typeof le=="function"&&le.length!=1&&(Y=ae=!1);var Le=this.__chain__,Fe=!!this.__actions__.length,$e=L&&!Le,ft=Y&&!Fe;if(!L&&ae){F=ft?F:new dt(this);var je=s.apply(F,z);return je.__actions__.push({func:Tg,args:[ce],thisArg:e}),new An(je,Le)}return $e&&ft?s.apply(this,z):(je=this.thru(ce),$e?x?je.value()[0]:je.value():je)})}),jn(["pop","push","shift","sort","splice","unshift"],function(s){var f=fa[s],m=/^(?:push|sort|unshift)$/.test(s)?"tap":"thru",x=/^(?:pop|shift)$/.test(s);N.prototype[s]=function(){var _=arguments;if(x&&!this.__chain__){var L=this.value();return f.apply(ot(L)?L:[],_)}return this[m](function(F){return f.apply(ot(F)?F:[],_)})}}),hi(dt.prototype,function(s,f){var m=N[f];if(m){var x=m.name+"";et.call(ga,x)||(ga[x]=[]),ga[x].push({name:f,func:m})}}),ga[sf(e,Z).name]=[{name:"wrapper",func:e}],dt.prototype.clone=jy,dt.prototype.reverse=qy,dt.prototype.value=yd,N.prototype.at=tM,N.prototype.chain=rM,N.prototype.commit=nM,N.prototype.next=iM,N.prototype.plant=sM,N.prototype.reverse=lM,N.prototype.toJSON=N.prototype.valueOf=N.prototype.value=aM,N.prototype.first=N.prototype.head,_s&&(N.prototype[_s]=oM),N},"runInContext"),vn=zu();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(qt._=vn,define(function(){return vn})):hn?((hn.exports=vn)._=vn,ea._=vn):qt._=vn}).call(Np)});var jk=Ue((iS,oS)=>{(function(e,t){typeof iS=="object"&&typeof oS!="undefined"?oS.exports=t():typeof define=="function"&&define.amd?define(t):e.stable=t()})(iS,function(){"use strict";var e=o(function(l,d){return t(l.slice(),d)},"stable");e.inplace=function(l,d){var h=t(l,d);return h!==l&&n(h,null,l.length,l),l};function t(l,d){typeof d!="function"&&(d=o(function(k,O){return String(k).localeCompare(O)},"comp"));var h=l.length;if(h<=1)return l;for(var c=new Array(h),v=1;vv&&(j=v),B>v&&(B=v),X=O,J=j;;)if(X{(function(){"use strict";var e={}.hasOwnProperty;function t(){for(var n=[],l=0;l{(function(e,t){typeof IS=="object"&&typeof FS!="undefined"?FS.exports=t():typeof define=="function"&&define.amd?define(t):(e=e||self,e.CodeMirror=t())})(IS,function(){"use strict";var e=navigator.userAgent,t=navigator.platform,n=/gecko\/\d/i.test(e),l=/MSIE \d/.test(e),d=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),h=/Edge\/(\d+)/.exec(e),c=l||d||h,v=c&&(l?document.documentMode||6:+(h||d)[1]),C=!h&&/WebKit\//.test(e),k=C&&/Qt\/\d+\.\d+/.test(e),O=!h&&/Chrome\//.test(e),j=/Opera\//.test(e),B=/Apple Computer/.test(navigator.vendor),X=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),J=/PhantomJS/.test(e),Z=B&&(/Mobile\/\w+/.test(e)||navigator.maxTouchPoints>2),R=/Android/.test(e),A=Z||R||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),I=Z||/Mac/.test(t),G=/\bCrOS\b/.test(e),K=/win/i.test(t),se=j&&e.match(/Version\/(\d*\.\d*)/);se&&(se=Number(se[1])),se&&se>=15&&(j=!1,C=!0);var ne=I&&(k||j&&(se==null||se<12.11)),pe=n||c&&v>=9;function me(r){return new RegExp("(^|\\s)"+r+"(?:$|\\s)\\s*")}o(me,"classTest");var xe=o(function(r,i){var u=r.className,a=me(i).exec(u);if(a){var p=u.slice(a.index+a[0].length);r.className=u.slice(0,a.index)+(p?a[1]+p:"")}},"rmClass");function Ve(r){for(var i=r.childNodes.length;i>0;--i)r.removeChild(r.firstChild);return r}o(Ve,"removeChildren");function tt(r,i){return Ve(r).appendChild(i)}o(tt,"removeChildrenAndAdd");function _e(r,i,u,a){var p=document.createElement(r);if(u&&(p.className=u),a&&(p.style.cssText=a),typeof i=="string")p.appendChild(document.createTextNode(i));else if(i)for(var g=0;g=i)return y+(i-g);y+=S-g,y+=u-y%u,g=S+1}}o(_t,"countColumn");var Ct=o(function(){this.id=null,this.f=null,this.time=0,this.handler=Hr(this.onTimeout,this)},"Delayed");Ct.prototype.onTimeout=function(r){r.id=0,r.time<=+new Date?r.f():setTimeout(r.handler,r.time-+new Date)},Ct.prototype.set=function(r,i){this.f=i;var u=+new Date+r;(!this.id||u=i)return a+Math.min(y,i-p);if(p+=g-a,p+=u-p%u,a=g+1,p>=i)return a}}o(Pr,"findColumn");var Gt=[""];function Yt(r){for(;Gt.length<=r;)Gt.push(Se(Gt)+" ");return Gt[r]}o(Yt,"spaceStr");function Se(r){return r[r.length-1]}o(Se,"lst");function Or(r,i){for(var u=[],a=0;a"\x80"&&(r.toUpperCase()!=r.toLowerCase()||cn.test(r))}o(Jt,"isWordCharBasic");function gr(r,i){return i?i.source.indexOf("\\w")>-1&&Jt(r)?!0:i.test(r):Jt(r)}o(gr,"isWordChar");function pt(r){for(var i in r)if(r.hasOwnProperty(i)&&r[i])return!1;return!0}o(pt,"isEmpty");var Ho=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function Cr(r){return r.charCodeAt(0)>=768&&Ho.test(r)}o(Cr,"isExtendingChar");function Ui(r,i,u){for(;(u<0?i>0:iu?-1:1;;){if(i==u)return i;var p=(i+u)/2,g=a<0?Math.ceil(p):Math.floor(p);if(g==i)return r(g)?i:u;r(g)?u=g:i=g+a}}o(pn,"findFirst");function zn(r,i,u,a){if(!r)return a(i,u,"ltr",0);for(var p=!1,g=0;gi||i==u&&y.to==i)&&(a(Math.max(y.from,i),Math.min(y.to,u),y.level==1?"rtl":"ltr",g),p=!0)}p||a(i,u,"ltr")}o(zn,"iterateBidiSections");var Si=null;function Ci(r,i,u){var a;Si=null;for(var p=0;pi)return p;g.to==i&&(g.from!=g.to&&u=="before"?a=p:Si=p),g.from==i&&(g.from!=g.to&&u!="before"?a=p:Si=p)}return a??Si}o(Ci,"getBidiPartAt");var $n=function(){var r="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",i="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";function u(E){return E<=247?r.charAt(E):1424<=E&&E<=1524?"R":1536<=E&&E<=1785?i.charAt(E-1536):1774<=E&&E<=2220?"r":8192<=E&&E<=8203?"w":E==8204?"b":"L"}o(u,"charType");var a=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,p=/[stwN]/,g=/[LRr]/,y=/[Lb1n]/,S=/[1n]/;function b(E,M,D){this.level=E,this.from=M,this.to=D}return o(b,"BidiSpan"),function(E,M){var D=M=="ltr"?"L":"R";if(E.length==0||M=="ltr"&&!a.test(E))return!1;for(var V=E.length,$=[],te=0;te-1&&(a[i]=p.slice(0,g).concat(p.slice(g+1)))}}}o(he,"off");function Te(r,i){var u=ee(r,i);if(!!u.length)for(var a=Array.prototype.slice.call(arguments,2),p=0;p0}o(Ft,"hasHandler");function Wr(r){r.prototype.on=function(i,u){H(this,i,u)},r.prototype.off=function(i,u){he(this,i,u)}}o(Wr,"eventMixin");function or(r){r.preventDefault?r.preventDefault():r.returnValue=!1}o(or,"e_preventDefault");function li(r){r.stopPropagation?r.stopPropagation():r.cancelBubble=!0}o(li,"e_stopPropagation");function ds(r){return r.defaultPrevented!=null?r.defaultPrevented:r.returnValue==!1}o(ds,"e_defaultPrevented");function lo(r){or(r),li(r)}o(lo,"e_stop");function bi(r){return r.target||r.srcElement}o(bi,"e_target");function el(r){var i=r.which;return i==null&&(r.button&1?i=1:r.button&2?i=3:r.button&4&&(i=2)),I&&r.ctrlKey&&i==1&&(i=3),i}o(el,"e_button");var hs=function(){if(c&&v<9)return!1;var r=_e("div");return"draggable"in r||"dragDrop"in r}(),dn;function id(r){if(dn==null){var i=_e("span","\u200B");tt(r,_e("span",[i,document.createTextNode("x")])),r.firstChild.offsetHeight!=0&&(dn=i.offsetWidth<=1&&i.offsetHeight>2&&!(c&&v<8))}var u=dn?_e("span","\u200B"):_e("span","\xA0",null,"display: inline-block; width: 1px; margin-right: -1px");return u.setAttribute("cm-text",""),u}o(id,"zeroWidthElement");var tl;function Qf(r){if(tl!=null)return tl;var i=tt(r,document.createTextNode("A\u062EA")),u=We(i,0,1).getBoundingClientRect(),a=We(i,1,2).getBoundingClientRect();return Ve(r),!u||u.left==u.right?!1:tl=a.right-u.right<3}o(Qf,"hasBadBidiRects");var rl=` +`)+fe+`return __p +}`;var dt=yb(function(){return yt(P,He+"return "+fe).apply(e,H)});if(dt.source=fe,$w(dt))throw dt;return dt}i(I2,"template");function F2(a){return zt(a).toLowerCase()}i(F2,"toLower");function B2(a){return zt(a).toUpperCase()}i(B2,"toUpper");function H2(a,f,m){if(a=zt(a),a&&(m||f===e))return Vl(a);if(!a||!(f=Si(f)))return a;var x=Xt(a),T=Xt(f),P=yi(x,T),H=ea(x,T)+1;return ks(x,P,H).join("")}i(H2,"trim");function z2(a,f,m){if(a=zt(a),a&&(m||f===e))return a.slice(0,Un(a)+1);if(!a||!(f=Si(f)))return a;var x=Xt(a),T=ea(x,Xt(f))+1;return ks(x,0,T).join("")}i(z2,"trimEnd");function U2(a,f,m){if(a=zt(a),a&&(m||f===e))return a.replace(ic,"");if(!a||!(f=Si(f)))return a;var x=Xt(a),T=yi(x,Xt(f));return ks(x,T).join("")}i(U2,"trimStart");function W2(a,f){var m=he,x=Re;if(_r(f)){var T="separator"in f?f.separator:T;m="length"in f?ct(f.length):m,x="omission"in f?Si(f.omission):x}a=zt(a);var P=a.length;if(xs(a)){var H=Xt(a);P=H.length}if(m>=P)return a;var $=m-mn(x);if($<1)return x;var X=H?ks(H,0,$).join(""):a.slice(0,$);if(T===e)return X+x;if(H&&($+=X.length-$),Vw(T)){if(a.slice($).search(T)){var le,ue=X;for(T.global||(T=Nc(T.source,zt(Vf.exec(T))+"g")),T.lastIndex=0;le=T.exec(ue);)var fe=le.index;X=X.slice(0,fe===e?$:fe)}}else if(a.indexOf(Si(T),$)!=$){var Ne=X.lastIndexOf(T);Ne>-1&&(X=X.slice(0,Ne))}return X+x}i(W2,"truncate");function $2(a){return a=zt(a),a&&Pt.test(a)?a.replace(Yt,fo):a}i($2,"unescape");var V2=mu(function(a,f,m){return a+(m?" ":"")+f.toUpperCase()}),Kw=Gg("toUpperCase");function vb(a,f,m){return a=zt(a),f=m?e:f,f===e?td(a)?kc(a):Zf(a):a.match(f)||[]}i(vb,"words");var yb=ut(function(a,f){try{return Qr(a,e,f)}catch(m){return $w(m)?m:new Je(m)}}),q2=Qo(function(a,f){return Zn(f,function(m){m=ar(m),bs(a,m,Uw(a[m],a))}),a});function j2(a){var f=a==null?0:a.length,m=We();return a=f?$t(a,function(x){if(typeof x[1]!="function")throw new Bi(l);return[m(x[0]),x[1]]}):[],ut(function(x){for(var T=-1;++TQe)return[];var m=At,x=Ar(a,At);f=We(f),a-=At;for(var T=Ec(x,f);++m0||f<0)?new $e(m):(a<0?m=m.takeRight(-a):a&&(m=m.drop(a)),f!==e&&(f=ct(f),m=f<0?m.dropRight(-f):m.take(f-a)),m)},$e.prototype.takeRightWhile=function(a){return this.reverse().takeWhile(a).reverse()},$e.prototype.toArray=function(){return this.take(At)},zi($e.prototype,function(a,f){var m=/^(?:filter|find|map|reject)|While$/.test(f),x=/^(?:head|last)$/.test(f),T=A[x?"take"+(f=="last"?"Right":""):f],P=x||/^find/.test(f);T&&(A.prototype[f]=function(){var H=this.__wrapped__,$=x?[1]:arguments,X=H instanceof $e,le=$[0],ue=X||at(H),fe=i(function(ht){var St=T.apply(A,Ii([ht],$));return x&&Ne?St[0]:St},"interceptor");ue&&m&&typeof le=="function"&&le.length!=1&&(X=ue=!1);var Ne=this.__chain__,He=!!this.__actions__.length,Ke=P&&!Ne,dt=X&&!He;if(!P&&ue){H=dt?H:new $e(this);var Ge=a.apply(H,$);return Ge.__actions__.push({func:rv,args:[fe],thisArg:e}),new Lt(Ge,Ne)}return Ke&&dt?a.apply(this,$):(Ge=this.thru(fe),Ke?x?Ge.value()[0]:Ge.value():Ge)})}),Zn(["pop","push","shift","sort","splice","unshift"],function(a){var f=rd[a],m=/^(?:push|sort|unshift)$/.test(a)?"tap":"thru",x=/^(?:pop|shift)$/.test(a);A.prototype[a]=function(){var T=arguments;if(x&&!this.__chain__){var P=this.value();return f.apply(at(P)?P:[],T)}return this[m](function(H){return f.apply(at(H)?H:[],T)})}}),zi($e.prototype,function(a,f){var m=A[f];if(m){var x=m.name+"";kt.call(ja,x)||(ja[x]=[]),ja[x].push({name:f,func:m})}}),ja[Sd(e,Q).name]=[{name:"wrapper",func:e}],$e.prototype.clone=Ir,$e.prototype.reverse=Oc,$e.prototype.value=gw,A.prototype.at=SR,A.prototype.chain=xR,A.prototype.commit=CR,A.prototype.next=_R,A.prototype.plant=bR,A.prototype.reverse=TR,A.prototype.toJSON=A.prototype.valueOf=A.prototype.value=kR,A.prototype.first=A.prototype.head,$a&&(A.prototype[$a]=ER),A},"runInContext"),gn=Yl();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Rt._=gn,define(function(){return gn})):Ys?((Ys.exports=gn)._=gn,Yf._=gn):Rt._=gn}).call(sp)});var PA=rt((kx,Nx)=>{(function(e,t){typeof kx=="object"&&typeof Nx<"u"?Nx.exports=t():typeof define=="function"&&define.amd?define(t):e.stable=t()})(kx,function(){"use strict";var e=i(function(s,l){return t(s.slice(),l)},"stable");e.inplace=function(s,l){var h=t(s,l);return h!==s&&n(h,null,s.length,s),s};function t(s,l){typeof l!="function"&&(l=i(function(b,k){return String(b).localeCompare(k)},"comp"));var h=s.length;if(h<=1)return s;for(var d=new Array(h),v=1;vv&&(R=v),I>v&&(I=v),z=k,q=R;;)if(z{(function(){"use strict";var e={}.hasOwnProperty;function t(){for(var l="",h=0;h{(function(e,t){typeof t_=="object"&&typeof r_<"u"?r_.exports=t():typeof define=="function"&&define.amd?define(t):(e=e||self,e.CodeMirror=t())})(t_,function(){"use strict";var e=navigator.userAgent,t=navigator.platform,n=/gecko\/\d/i.test(e),s=/MSIE \d/.test(e),l=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),h=/Edge\/(\d+)/.exec(e),d=s||l||h,v=d&&(s?document.documentMode||6:+(h||l)[1]),S=!h&&/WebKit\//.test(e),b=S&&/Qt\/\d+\.\d+/.test(e),k=!h&&/Chrome\/(\d+)/.exec(e),R=k&&+k[1],I=/Opera\//.test(e),z=/Apple Computer/.test(navigator.vendor),q=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),Q=/PhantomJS/.test(e),ne=z&&(/Mobile\/\w+/.test(e)||navigator.maxTouchPoints>2),D=/Android/.test(e),L=ne||D||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),B=ne||/Mac/.test(t),j=/\bCrOS\b/.test(e),re=/win/i.test(t),Z=I&&e.match(/Version\/(\d*\.\d*)/);Z&&(Z=Number(Z[1])),Z&&Z>=15&&(I=!1,S=!0);var oe=B&&(b||I&&(Z==null||Z<12.11)),he=n||d&&v>=9;function Re(r){return new RegExp("(^|\\s)"+r+"(?:$|\\s)\\s*")}i(Re,"classTest");var Ee=i(function(r,o){var c=r.className,u=Re(o).exec(c);if(u){var p=c.slice(u.index+u[0].length);r.className=c.slice(0,u.index)+(p?u[1]+p:"")}},"rmClass");function Ye(r){for(var o=r.childNodes.length;o>0;--o)r.removeChild(r.firstChild);return r}i(Ye,"removeChildren");function tt(r,o){return Ye(r).appendChild(o)}i(tt,"removeChildrenAndAdd");function xe(r,o,c,u){var p=document.createElement(r);if(c&&(p.className=c),u&&(p.style.cssText=u),typeof o=="string")p.appendChild(document.createTextNode(o));else if(o)for(var g=0;g=o)return y+(o-g);y+=C-g,y+=c-y%c,g=C+1}}i(Ft,"countColumn");var se=i(function(){this.id=null,this.f=null,this.time=0,this.handler=yr(this.onTimeout,this)},"Delayed");se.prototype.onTimeout=function(r){r.id=0,r.time<=+new Date?r.f():setTimeout(r.handler,r.time-+new Date)},se.prototype.set=function(r,o){this.f=o;var c=+new Date+r;(!this.id||c=o)return u+Math.min(y,o-p);if(p+=g-u,p+=c-p%c,u=g+1,p>=o)return u}}i(En,"findColumn");var no=[""];function Ho(r){for(;no.length<=r;)no.push(lt(no)+" ");return no[r]}i(Ho,"spaceStr");function lt(r){return r[r.length-1]}i(lt,"lst");function wr(r,o){for(var c=[],u=0;u"\x80"&&(r.toUpperCase()!=r.toLowerCase()||Bn.test(r))}i(Mi,"isWordCharBasic");function Gr(r,o){return o?o.source.indexOf("\\w")>-1&&Mi(r)?!0:o.test(r):Mi(r)}i(Gr,"isWordChar");function Yr(r){for(var o in r)if(r.hasOwnProperty(o)&&r[o])return!1;return!0}i(Yr,"isEmpty");var oo=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function hi(r){return r.charCodeAt(0)>=768&&oo.test(r)}i(hi,"isExtendingChar");function Hn(r,o,c){for(;(c<0?o>0:oc?-1:1;;){if(o==c)return o;var p=(o+c)/2,g=u<0?Math.ceil(p):Math.floor(p);if(g==o)return r(g)?o:c;r(g)?c=g:o=g+u}}i(so,"findFirst");function bl(r,o,c,u){if(!r)return u(o,c,"ltr",0);for(var p=!1,g=0;go||o==c&&y.to==o)&&(u(Math.max(y.from,o),Math.min(y.to,c),y.level==1?"rtl":"ltr",g),p=!0)}p||u(o,c,"ltr")}i(bl,"iterateBidiSections");var Y=null;function ee(r,o,c){var u;Y=null;for(var p=0;po)return p;g.to==o&&(g.from!=g.to&&c=="before"?u=p:Y=p),g.from==o&&(g.from!=g.to&&c!="before"?u=p:Y=p)}return u??Y}i(ee,"getBidiPartAt");var Ce=function(){var r="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",o="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";function c(E){return E<=247?r.charAt(E):1424<=E&&E<=1524?"R":1536<=E&&E<=1785?o.charAt(E-1536):1774<=E&&E<=2220?"r":8192<=E&&E<=8203?"w":E==8204?"b":"L"}i(c,"charType");var u=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,p=/[stwN]/,g=/[LRr]/,y=/[Lb1n]/,C=/[1n]/;function _(E,O,F){this.level=E,this.from=O,this.to=F}return i(_,"BidiSpan"),function(E,O){var F=O=="ltr"?"L":"R";if(E.length==0||O=="ltr"&&!u.test(E))return!1;for(var K=E.length,V=[],te=0;te-1&&(u[o]=p.slice(0,g).concat(p.slice(g+1)))}}}i(Yt,"off");function Mt(r,o){var c=Xr(r,o);if(c.length)for(var u=Array.prototype.slice.call(arguments,2),p=0;p0}i(dn,"hasHandler");function zn(r){r.prototype.on=function(o,c){ze(this,o,c)},r.prototype.off=function(o,c){Yt(this,o,c)}}i(zn,"eventMixin");function kr(r){r.preventDefault?r.preventDefault():r.returnValue=!1}i(kr,"e_preventDefault");function gs(r){r.stopPropagation?r.stopPropagation():r.cancelBubble=!0}i(gs,"e_stopPropagation");function bn(r){return r.defaultPrevented!=null?r.defaultPrevented:r.returnValue==!1}i(bn,"e_defaultPrevented");function Aa(r){kr(r),gs(r)}i(Aa,"e_stop");function Pa(r){return r.target||r.srcElement}i(Pa,"e_target");function nc(r){var o=r.which;return o==null&&(r.button&1?o=1:r.button&2?o=3:r.button&4&&(o=2)),B&&r.ctrlKey&&o==1&&(o=3),o}i(nc,"e_button");var ic=function(){if(d&&v<9)return!1;var r=xe("div");return"draggable"in r||"dragDrop"in r}(),oc;function $f(r){if(oc==null){var o=xe("span","\u200B");tt(r,xe("span",[o,document.createTextNode("x")])),r.firstChild.offsetHeight!=0&&(oc=o.offsetWidth<=1&&o.offsetHeight>2&&!(d&&v<8))}var c=oc?xe("span","\u200B"):xe("span","\xA0",null,"display: inline-block; width: 1px; margin-right: -1px");return c.setAttribute("cm-text",""),c}i($f,"zeroWidthElement");var sc;function Fp(r){if(sc!=null)return sc;var o=tt(r,document.createTextNode("A\u062EA")),c=je(o,0,1).getBoundingClientRect(),u=je(o,1,2).getBoundingClientRect();return Ye(r),!c||c.left==c.right?!1:sc=u.right-c.right<3}i(Fp,"hasBadBidiRects");var kl=` -b`.split(/\n/).length!=3?function(r){for(var i=0,u=[],a=r.length;i<=a;){var p=r.indexOf(` -`,i);p==-1&&(p=r.length);var g=r.slice(i,r.charAt(p-1)=="\r"?p-1:p),y=g.indexOf("\r");y!=-1?(u.push(g.slice(0,y)),i+=y+1):(u.push(g),i=p+1)}return u}:function(r){return r.split(/\r\n?|\n/)},od=window.getSelection?function(r){try{return r.selectionStart!=r.selectionEnd}catch(i){return!1}}:function(r){var i;try{i=r.ownerDocument.selection.createRange()}catch(u){}return!i||i.parentElement()!=r?!1:i.compareEndPoints("StartToEnd",i)!=0},Zf=function(){var r=_e("div");return"oncopy"in r?!0:(r.setAttribute("oncopy","return;"),typeof r.oncopy=="function")}(),wu=null;function sd(r){if(wu!=null)return wu;var i=tt(r,_e("span","x")),u=i.getBoundingClientRect(),a=We(i,0,1).getBoundingClientRect();return wu=Math.abs(u.left-a.left)>1}o(sd,"hasBadZoomedRects");var zl={},ms={};function ld(r,i){arguments.length>2&&(i.dependencies=Array.prototype.slice.call(arguments,2)),zl[r]=i}o(ld,"defineMode");function Jf(r,i){ms[r]=i}o(Jf,"defineMIME");function nl(r){if(typeof r=="string"&&ms.hasOwnProperty(r))r=ms[r];else if(r&&typeof r.name=="string"&&ms.hasOwnProperty(r.name)){var i=ms[r.name];typeof i=="string"&&(i={name:i}),r=si(i,r),r.name=i.name}else{if(typeof r=="string"&&/^[\w\-]+\/[\w\-]+\+xml$/.test(r))return nl("application/xml");if(typeof r=="string"&&/^[\w\-]+\/[\w\-]+\+json$/.test(r))return nl("application/json")}return typeof r=="string"?{name:r}:r||{name:"null"}}o(nl,"resolveMode");function xu(r,i){i=nl(i);var u=zl[i.name];if(!u)return xu(r,"text/plain");var a=u(r,i);if(Wo.hasOwnProperty(i.name)){var p=Wo[i.name];for(var g in p)!p.hasOwnProperty(g)||(a.hasOwnProperty(g)&&(a["_"+g]=a[g]),a[g]=p[g])}if(a.name=i.name,i.helperType&&(a.helperType=i.helperType),i.modeProps)for(var y in i.modeProps)a[y]=i.modeProps[y];return a}o(xu,"getMode");var Wo={};function ad(r,i){var u=Wo.hasOwnProperty(r)?Wo[r]:Wo[r]={};Zt(i,u)}o(ad,"extendMode");function Uo(r,i){if(i===!0)return i;if(r.copyState)return r.copyState(i);var u={};for(var a in i){var p=i[a];p instanceof Array&&(p=p.concat([])),u[a]=p}return u}o(Uo,"copyState");function $l(r,i){for(var u;r.innerMode&&(u=r.innerMode(i),!(!u||u.mode==r));)i=u.state,r=u.mode;return u||{mode:r,state:i}}o($l,"innerMode");function ec(r,i,u){return r.startState?r.startState(i,u):!0}o(ec,"startState");var jt=o(function(r,i,u){this.pos=this.start=0,this.string=r,this.tabSize=i||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=u},"StringStream");jt.prototype.eol=function(){return this.pos>=this.string.length},jt.prototype.sol=function(){return this.pos==this.lineStart},jt.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},jt.prototype.next=function(){if(this.posi},jt.prototype.eatSpace=function(){for(var r=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>r},jt.prototype.skipToEnd=function(){this.pos=this.string.length},jt.prototype.skipTo=function(r){var i=this.string.indexOf(r,this.pos);if(i>-1)return this.pos=i,!0},jt.prototype.backUp=function(r){this.pos-=r},jt.prototype.column=function(){return this.lastColumnPos0?null:(g&&i!==!1&&(this.pos+=g[0].length),g)}},jt.prototype.current=function(){return this.string.slice(this.start,this.pos)},jt.prototype.hideFirstChars=function(r,i){this.lineStart+=r;try{return i()}finally{this.lineStart-=r}},jt.prototype.lookAhead=function(r){var i=this.lineOracle;return i&&i.lookAhead(r)},jt.prototype.baseToken=function(){var r=this.lineOracle;return r&&r.baseToken(this.pos)};function Me(r,i){if(i-=r.first,i<0||i>=r.size)throw new Error("There is no line "+(i+r.first)+" in the document.");for(var u=r;!u.lines;)for(var a=0;;++a){var p=u.children[a],g=p.chunkSize();if(i=r.first&&iu?ue(u,Me(r,u).text.length):ud(i,Me(r,i.line).text.length)}o(He,"clipPos");function ud(r,i){var u=r.ch;return u==null||u>i?ue(r.line,i):u<0?ue(r.line,0):r}o(ud,"clipToLen");function ql(r,i){for(var u=[],a=0;athis.maxLookAhead&&(this.maxLookAhead=r),i},ui.prototype.baseToken=function(r){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=r;)this.baseTokenPos+=2;var i=this.baseTokens[this.baseTokenPos+1];return{type:i&&i.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-r}},ui.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},ui.fromSaved=function(r,i,u){return i instanceof uo?new ui(r,Uo(r.mode,i.state),u,i.lookAhead):new ui(r,Uo(r.mode,i),u)},ui.prototype.save=function(r){var i=r!==!1?Uo(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new uo(i,this.maxLookAhead):i};function tc(r,i,u,a){var p=[r.state.modeGen],g={};Gl(r,i.text,r.doc.mode,u,function(E,M){return p.push(E,M)},g,a);for(var y=u.state,S=o(function(E){u.baseTokens=p;var M=r.state.overlays[E],D=1,V=0;u.state=!0,Gl(r,i.text,M.mode,u,function($,te){for(var oe=D;V<$;){var de=p[D];de>$&&p.splice(D,1,$,p[D+1],de),D+=2,V=Math.min($,de)}if(!!te)if(M.opaque)p.splice(oe,D-oe,$,"overlay "+te),D=oe+2;else for(;oer.options.maxHighlightLength&&Uo(r.doc.mode,a.state),g=tc(r,i,a);p&&(a.state=p),i.stateAfter=a.save(!p),i.styles=g.styles,g.classes?i.styleClasses=g.classes:i.styleClasses&&(i.styleClasses=null),u===r.doc.highlightFrontier&&(r.doc.modeFrontier=Math.max(r.doc.modeFrontier,++r.doc.highlightFrontier))}return i.styles}o(_u,"getLineStyles");function $o(r,i,u){var a=r.doc,p=r.display;if(!a.mode.startState)return new ui(a,!0,i);var g=Yl(r,i,u),y=g>a.first&&Me(a,g-1).stateAfter,S=y?ui.fromSaved(a,y,g):new ui(a,ec(a.mode),g);return a.iter(g,i,function(b){vs(r,b.text,S);var E=S.line;b.stateAfter=E==i-1||E%5==0||E>=p.viewFrom&&Ei.start)return g}throw new Error("Mode "+r.name+" failed to advance stream.")}o(ol,"readToken");var Vl=o(function(r,i,u){this.start=r.start,this.end=r.pos,this.string=r.current(),this.type=i||null,this.state=u},"Token");function Kl(r,i,u,a){var p=r.doc,g=p.mode,y;i=He(p,i);var S=Me(p,i.line),b=$o(r,i.line,u),E=new jt(S.text,r.options.tabSize,b),M;for(a&&(M=[]);(a||E.posr.options.maxHighlightLength?(S=!1,y&&vs(r,i,a,M.pos),M.pos=i.length,D=null):D=fo(ol(u,M,a.state,V),g),V){var $=V[0].name;$&&(D="m-"+(D?$+" "+D:$))}if(!S||E!=D){for(;by;--S){if(S<=g.first)return g.first;var b=Me(g,S-1),E=b.stateAfter;if(E&&(!u||S+(E instanceof uo?E.lookAhead:0)<=g.modeFrontier))return S;var M=_t(b.text,null,r.options.tabSize);(p==null||a>M)&&(p=S-1,a=M)}return p}o(Yl,"findStartLine");function rc(r,i){if(r.modeFrontier=Math.min(r.modeFrontier,i),!(r.highlightFrontieru;a--){var p=Me(r,a).stateAfter;if(p&&(!(p instanceof uo)||a+p.lookAhead=i:g.to>i);(a||(a=[])).push(new co(y,g.from,b?null:g.to))}}return a}o(fd,"markedSpansBefore");function cd(r,i,u){var a;if(r)for(var p=0;p=i:g.to>i);if(S||g.from==i&&y.type=="bookmark"&&(!u||g.marker.insertLeft)){var b=g.from==null||(y.inclusiveLeft?g.from<=i:g.from0&&S)for(var Ne=0;Ne0)){var M=[b,1],D=ze(E.from,S.from),V=ze(E.to,S.to);(D<0||!y.inclusiveLeft&&!D)&&M.push({from:E.from,to:S.from}),(V>0||!y.inclusiveRight&&!V)&&M.push({from:S.to,to:E.to}),p.splice.apply(p,M),b+=M.length-3}}return p}o(Nu,"removeReadOnlyRanges");function lc(r){var i=r.markedSpans;if(!!i){for(var u=0;ui)&&(!a||Lu(a,g.marker)<0)&&(a=g.marker)}return a}o(Re,"collapsedSpanAround");function sl(r,i,u,a,p){var g=Me(r,i),y=_i&&g.markedSpans;if(y)for(var S=0;S=0&&D<=0||M<=0&&D>=0)&&(M<=0&&(b.marker.inclusiveRight&&p.inclusiveLeft?ze(E.to,u)>=0:ze(E.to,u)>0)||M>=0&&(b.marker.inclusiveRight&&p.inclusiveLeft?ze(E.from,a)<=0:ze(E.from,a)<0)))return!0}}}o(sl,"conflictingCollapsedRange");function vr(r){for(var i;i=Nt(r);)r=i.find(-1,!0).line;return r}o(vr,"visualLine");function Pu(r){for(var i;i=P(r);)r=i.find(1,!0).line;return r}o(Pu,"visualLineEnd");function ye(r){for(var i,u;i=P(r);)r=i.find(1,!0).line,(u||(u=[])).push(r);return u}o(ye,"visualLineContinued");function jo(r,i){var u=Me(r,i),a=vr(u);return u==a?i:vt(a)}o(jo,"visualLineNo");function pd(r,i){if(i>r.lastLine())return i;var u=Me(r,i),a;if(!qt(r,u))return i;for(;a=P(u);)u=a.find(1,!0).line;return vt(u)+1}o(pd,"visualLineEndNo");function qt(r,i){var u=_i&&i.markedSpans;if(u){for(var a=void 0,p=0;pi.maxLineLength&&(i.maxLineLength=p,i.maxLine=a)})}o(zi,"findMaxLine");var Ce=o(function(r,i,u){this.text=r,ac(this,i),this.height=u?u(this):1},"Line");Ce.prototype.lineNo=function(){return vt(this)},Wr(Ce);function ta(r,i,u,a){r.text=i,r.stateAfter&&(r.stateAfter=null),r.styles&&(r.styles=null),r.order!=null&&(r.order=null),lc(r),ac(r,u);var p=a?a(r):1;p!=r.height&&ai(r,p)}o(ta,"updateLine");function Ou(r){r.parent=null,lc(r)}o(Ou,"cleanUpLine");var nt={},uc={};function fi(r,i){if(!r||/^\s*$/.test(r))return null;var u=i.addModeClass?uc:nt;return u[r]||(u[r]=r.replace(/\S+/g,"cm-$&"))}o(fi,"interpretTokenStyle");function ll(r,i){var u=St("span",null,null,C?"padding-right: .1px":null),a={pre:St("pre",[u],"CodeMirror-line"),content:u,col:0,pos:0,cm:r,trailingSpace:!1,splitSpaces:r.getOption("lineWrapping")};i.measure={};for(var p=0;p<=(i.rest?i.rest.length:0);p++){var g=p?i.rest[p-1]:i.line,y=void 0;a.pos=0,a.addToken=ra,Qf(r.display.measure)&&(y=Mn(g,r.doc.direction))&&(a.addToken=dd(a.addToken,y)),a.map=[];var S=i!=r.display.externalMeasured&&vt(g);Vt(g,a,_u(r,g,S)),g.styleClasses&&(g.styleClasses.bgClass&&(a.bgClass=nr(g.styleClasses.bgClass,a.bgClass||"")),g.styleClasses.textClass&&(a.textClass=nr(g.styleClasses.textClass,a.textClass||""))),a.map.length==0&&a.map.push(0,0,a.content.appendChild(id(r.display.measure))),p==0?(i.measure.map=a.map,i.measure.cache={}):((i.measure.maps||(i.measure.maps=[])).push(a.map),(i.measure.caches||(i.measure.caches=[])).push({}))}if(C){var b=a.content.lastChild;(/\bcm-tab\b/.test(b.className)||b.querySelector&&b.querySelector(".cm-tab"))&&(a.content.className="cm-tab-wrap-hack")}return Te(r,"renderLine",r,i.line,a.pre),a.pre.className&&(a.textClass=nr(a.pre.className,a.textClass||"")),a}o(ll,"buildLineContent");function Ur(r){var i=_e("span","\u2022","cm-invalidchar");return i.title="\\u"+r.charCodeAt(0).toString(16),i.setAttribute("aria-label",i.title),i}o(Ur,"defaultSpecialCharPlaceholder");function ra(r,i,u,a,p,g,y){if(!!i){var S=r.splitSpaces?jn(i,r.trailingSpace):i,b=r.cm.state.specialChars,E=!1,M;if(!b.test(i))r.col+=i.length,M=document.createTextNode(S),r.map.push(r.pos,r.pos+i.length,M),c&&v<9&&(E=!0),r.pos+=i.length;else{M=document.createDocumentFragment();for(var D=0;;){b.lastIndex=D;var V=b.exec(i),$=V?V.index-D:i.length-D;if($){var te=document.createTextNode(S.slice(D,D+$));c&&v<9?M.appendChild(_e("span",[te])):M.appendChild(te),r.map.push(r.pos,r.pos+$,te),r.col+=$,r.pos+=$}if(!V)break;D+=$+1;var oe=void 0;if(V[0]==" "){var de=r.cm.options.tabSize,ge=de-r.col%de;oe=M.appendChild(_e("span",Yt(ge),"cm-tab")),oe.setAttribute("role","presentation"),oe.setAttribute("cm-text"," "),r.col+=ge}else V[0]=="\r"||V[0]==` -`?(oe=M.appendChild(_e("span",V[0]=="\r"?"\u240D":"\u2424","cm-invalidchar")),oe.setAttribute("cm-text",V[0]),r.col+=1):(oe=r.cm.options.specialCharPlaceholder(V[0]),oe.setAttribute("cm-text",V[0]),c&&v<9?M.appendChild(_e("span",[oe])):M.appendChild(oe),r.col+=1);r.map.push(r.pos,r.pos+1,oe),r.pos++}}if(r.trailingSpace=S.charCodeAt(i.length-1)==32,u||a||p||E||g||y){var be=u||"";a&&(be+=a),p&&(be+=p);var ve=_e("span",[M],be,g);if(y)for(var Ne in y)y.hasOwnProperty(Ne)&&Ne!="style"&&Ne!="class"&&ve.setAttribute(Ne,y[Ne]);return r.content.appendChild(ve)}r.content.appendChild(M)}}o(ra,"buildToken");function jn(r,i){if(r.length>1&&!/ /.test(r))return r;for(var u=i,a="",p=0;pE&&D.from<=E));V++);if(D.to>=M)return r(u,a,p,g,y,S,b);r(u,a.slice(0,D.to-E),p,g,null,S,b),g=null,a=a.slice(D.to-E),E=D.to}}}o(dd,"buildTokenBadBidi");function Mu(r,i,u,a){var p=!a&&u.widgetNode;p&&r.map.push(r.pos,r.pos+i,p),!a&&r.cm.display.input.needsContentAttribute&&(p||(p=r.content.appendChild(document.createElement("span"))),p.setAttribute("cm-marker",u.id)),p&&(r.cm.display.input.setUneditable(p),r.content.appendChild(p)),r.pos+=i,r.trailingSpace=!1}o(Mu,"buildCollapsedSpan");function Vt(r,i,u){var a=r.markedSpans,p=r.text,g=0;if(!a){for(var y=1;yb||it.collapsed&&De.to==b&&De.from==b)){if(De.to!=null&&De.to!=b&&$>De.to&&($=De.to,oe=""),it.className&&(te+=" "+it.className),it.css&&(V=(V?V+";":"")+it.css),it.startStyle&&De.from==b&&(de+=" "+it.startStyle),it.endStyle&&De.to==$&&(Ne||(Ne=[])).push(it.endStyle,De.to),it.title&&((be||(be={})).title=it.title),it.attributes)for(var Tt in it.attributes)(be||(be={}))[Tt]=it.attributes[Tt];it.collapsed&&(!ge||Lu(ge.marker,it)<0)&&(ge=De)}else De.from>b&&$>De.from&&($=De.from)}if(Ne)for(var br=0;br=S)break;for(var Sn=Math.min(S,$);;){if(M){var Cn=b+M.length;if(!ge){var dr=Cn>Sn?M.slice(0,Sn-b):M;i.addToken(i,dr,D?D+te:te,de,b+dr.length==$?oe:"",V,be)}if(Cn>=Sn){M=M.slice(Sn-b),b=Sn;break}b=Cn,de=""}M=p.slice(g,g=u[E++]),D=fi(u[E++],i.cm.options)}}}o(Vt,"insertLineContent");function xs(r,i,u){this.line=i,this.rest=ye(i),this.size=this.rest?vt(Se(this.rest))-u+1:1,this.node=this.text=null,this.hidden=qt(r,i)}o(xs,"LineView");function qo(r,i,u){for(var a=[],p,g=i;g2&&g.push((b.bottom+E.top)/2-u.top)}}g.push(u.bottom-u.top)}}o(cc,"ensureLineHeights");function Wu(r,i,u){if(r.line==i)return{map:r.measure.map,cache:r.measure.cache};for(var a=0;au)return{map:r.measure.maps[p],cache:r.measure.caches[p],before:!0}}o(Wu,"mapFromLineView");function gd(r,i){i=vr(i);var u=vt(i),a=r.display.externalMeasured=new xs(r.doc,i,u);a.lineN=u;var p=a.built=ll(r,a);return a.text=p.pre,tt(r.display.lineMeasure,p.pre),a}o(gd,"updateExternalMeasurement");function Uu(r,i,u,a){return Ti(r,qn(r,i),u,a)}o(Uu,"measureChar");function la(r,i){if(i>=r.display.viewFrom&&i=u.lineN&&ii)&&(g=b-S,p=g-1,i>=b&&(y="right")),p!=null){if(a=r[E+2],S==b&&u==(a.insertLeft?"left":"right")&&(y=u),u=="left"&&p==0)for(;E&&r[E-2]==r[E-3]&&r[E-1].insertLeft;)a=r[(E-=3)+2],y="left";if(u=="right"&&p==b-S)for(;E=0&&(u=r[p]).left==u.right;p--);return u}o(dc,"getUsefulRect");function Vi(r,i,u,a){var p=aa(i.map,u,a),g=p.node,y=p.start,S=p.end,b=p.collapse,E;if(g.nodeType==3){for(var M=0;M<4;M++){for(;y&&Cr(i.line.text.charAt(p.coverStart+y));)--y;for(;p.coverStart+S0&&(b=a="right");var D;r.options.lineWrapping&&(D=g.getClientRects()).length>1?E=D[a=="right"?D.length-1:0]:E=g.getBoundingClientRect()}if(c&&v<9&&!y&&(!E||!E.left&&!E.right)){var V=g.parentNode.getClientRects()[0];V?E={left:V.left,right:V.left+ua(r.display),top:V.top,bottom:V.bottom}:E=pc}for(var $=E.top-i.rect.top,te=E.bottom-i.rect.top,oe=($+te)/2,de=i.view.measure.heights,ge=0;ge=a.text.length?(b=a.text.length,E="before"):b<=0&&(b=0,E="after"),!S)return y(E=="before"?b-1:b,E=="before");function M(te,oe,de){var ge=S[oe],be=ge.level==1;return y(de?te-1:te,be!=de)}o(M,"getBidi");var D=Ci(S,b,E),V=Si,$=M(b,D,E=="before");return V!=null&&($.other=M(b,V,E!="before")),$}o(Vn,"cursorCoords");function zu(r,i){var u=0;i=He(r.doc,i),r.options.lineWrapping||(u=ua(r.display)*i.ch);var a=Me(r.doc,i.line),p=hn(a)+Ss(r.display);return{left:u,right:u,top:p,bottom:p+a.height}}o(zu,"estimateCoords");function vn(r,i,u,a,p){var g=ue(r,i,u);return g.xRel=p,a&&(g.outside=a),g}o(vn,"PosWithInfo");function q(r,i,u){var a=r.doc;if(u+=r.display.viewOffset,u<0)return vn(a.first,0,null,-1,-1);var p=ao(a,u),g=a.first+a.size-1;if(p>g)return vn(a.first+a.size-1,Me(a,g).text.length,null,1,1);i<0&&(i=0);for(var y=Me(a,p);;){var S=Qe(r,y,p,i,u),b=Re(y,S.ch+(S.xRel>0||S.outside>0?1:0));if(!b)return S;var E=b.find(1);if(E.line==p)return E;y=Me(a,p=E.line)}}o(q,"coordsChar");function re(r,i,u,a){a-=gn(i);var p=i.text.length,g=pn(function(y){return Ti(r,u,y-1).bottom<=a},p,0);return p=pn(function(y){return Ti(r,u,y).top>a},g,p),{begin:g,end:p}}o(re,"wrappedLineExtent");function Q(r,i,u,a){u||(u=qn(r,i));var p=ci(r,i,Ti(r,u,a),"line").top;return re(r,i,u,p)}o(Q,"wrappedLineExtentChar");function Pe(r,i,u,a){return r.bottom<=u?!1:r.top>u?!0:(a?r.left:r.right)>i}o(Pe,"boxIsAfter");function Qe(r,i,u,a,p){p-=hn(i);var g=qn(r,i),y=gn(i),S=0,b=i.text.length,E=!0,M=Mn(i,r.doc.direction);if(M){var D=(r.options.lineWrapping?Mr:bt)(r,i,u,g,M,a,p);E=D.level!=1,S=E?D.from:D.to-1,b=E?D.to:D.from-1}var V=null,$=null,te=pn(function(Ie){var De=Ti(r,g,Ie);return De.top+=y,De.bottom+=y,Pe(De,a,p,!1)?(De.top<=p&&De.left<=a&&(V=Ie,$=De),!0):!1},S,b),oe,de,ge=!1;if($){var be=a-$.left<$.right-a,ve=be==E;te=V+(ve?0:1),de=ve?"after":"before",oe=be?$.left:$.right}else{!E&&(te==b||te==S)&&te++,de=te==0?"after":te==i.text.length?"before":Ti(r,g,te-(E?1:0)).bottom+y<=p==E?"after":"before";var Ne=Vn(r,ue(u,te,de),"line",i,g);oe=Ne.left,ge=p=Ne.bottom?1:0}return te=Ui(i.text,te,1),vn(u,te,de,ge,a-oe)}o(Qe,"coordsCharInner");function bt(r,i,u,a,p,g,y){var S=pn(function(D){var V=p[D],$=V.level!=1;return Pe(Vn(r,ue(u,$?V.to:V.from,$?"before":"after"),"line",i,a),g,y,!0)},0,p.length-1),b=p[S];if(S>0){var E=b.level!=1,M=Vn(r,ue(u,E?b.from:b.to,E?"after":"before"),"line",i,a);Pe(M,g,y,!0)&&M.top>y&&(b=p[S-1])}return b}o(bt,"coordsBidiPart");function Mr(r,i,u,a,p,g,y){var S=re(r,i,a,y),b=S.begin,E=S.end;/\s/.test(i.text.charAt(E-1))&&E--;for(var M=null,D=null,V=0;V=E||$.to<=b)){var te=$.level!=1,oe=Ti(r,a,te?Math.min(E,$.to)-1:Math.max(b,$.from)).right,de=oede)&&(M=$,D=de)}}return M||(M=p[p.length-1]),M.fromE&&(M={from:M.from,to:E,level:M.level}),M}o(Mr,"coordsBidiPartWrapped");var mt;function Cs(r){if(r.cachedTextHeight!=null)return r.cachedTextHeight;if(mt==null){mt=_e("pre",null,"CodeMirror-line-like");for(var i=0;i<49;++i)mt.appendChild(document.createTextNode("x")),mt.appendChild(_e("br"));mt.appendChild(document.createTextNode("x"))}tt(r.measure,mt);var u=mt.offsetHeight/50;return u>3&&(r.cachedTextHeight=u),Ve(r.measure),u||1}o(Cs,"textHeight");function ua(r){if(r.cachedCharWidth!=null)return r.cachedCharWidth;var i=_e("span","xxxxxxxxxx"),u=_e("pre",[i],"CodeMirror-line-like");tt(r.measure,u);var a=i.getBoundingClientRect(),p=(a.right-a.left)/10;return p>2&&(r.cachedCharWidth=p),p||10}o(ua,"charWidth");function Kn(r){for(var i=r.display,u={},a={},p=i.gutters.clientLeft,g=i.gutters.firstChild,y=0;g;g=g.nextSibling,++y){var S=r.display.gutterSpecs[y].className;u[S]=g.offsetLeft+g.clientLeft+p,a[S]=g.clientWidth}return{fixedPos:fa(i),gutterTotalWidth:i.gutters.offsetWidth,gutterLeft:u,gutterWidth:a,wrapperWidth:i.wrapper.clientWidth}}o(Kn,"getDimensions");function fa(r){return r.scroller.getBoundingClientRect().left-r.sizer.getBoundingClientRect().left}o(fa,"compensateForHScroll");function Bm(r){var i=Cs(r.display),u=r.options.lineWrapping,a=u&&Math.max(5,r.display.scroller.clientWidth/ua(r.display)-3);return function(p){if(qt(r.doc,p))return 0;var g=0;if(p.widgets)for(var y=0;y0&&(E=Me(r.doc,b.line).text).length==b.ch){var M=_t(E,E.length,r.options.tabSize)-E.length;b=ue(b.line,Math.max(0,Math.round((g-sa(r.display).left)/ua(r.display))-M))}return b}o(po,"posFromMouse");function ho(r,i){if(i>=r.display.viewTo||(i-=r.display.viewFrom,i<0))return null;for(var u=r.display.view,a=0;ai)&&(p.updateLineNumbers=i),r.curOp.viewChanged=!0,i>=p.viewTo)_i&&jo(r.doc,i)p.viewFrom?Xo(r):(p.viewFrom+=a,p.viewTo+=a);else if(i<=p.viewFrom&&u>=p.viewTo)Xo(r);else if(i<=p.viewFrom){var g=fl(r,u,u+a,1);g?(p.view=p.view.slice(g.index),p.viewFrom=g.lineN,p.viewTo+=a):Xo(r)}else if(u>=p.viewTo){var y=fl(r,i,i,-1);y?(p.view=p.view.slice(0,y.index),p.viewTo=y.lineN):Xo(r)}else{var S=fl(r,i,i,-1),b=fl(r,u,u+a,1);S&&b?(p.view=p.view.slice(0,S.index).concat(qo(r,S.lineN,b.lineN)).concat(p.view.slice(b.index)),p.viewTo+=a):Xo(r)}var E=p.externalMeasured;E&&(u=p.lineN&&i=a.viewTo)){var g=a.view[ho(r,i)];if(g.node!=null){var y=g.changes||(g.changes=[]);ut(y,u)==-1&&y.push(u)}}}o(Es,"regLineChange");function Xo(r){r.display.viewFrom=r.display.viewTo=r.doc.first,r.display.view=[],r.display.viewOffset=0}o(Xo,"resetView");function fl(r,i,u,a){var p=ho(r,i),g,y=r.display.view;if(!_i||u==r.doc.first+r.doc.size)return{index:p,lineN:u};for(var S=r.display.viewFrom,b=0;b0){if(p==y.length-1)return null;g=S+y[p].size-i,p++}else g=S-i;i+=g,u+=g}for(;jo(r.doc,u)!=u;){if(p==(a<0?0:y.length-1))return null;u+=a*y[p-(a<0?1:0)].size,p+=a}return{index:p,lineN:u}}o(fl,"viewCuttingPoint");function Ry(r,i,u){var a=r.display,p=a.view;p.length==0||i>=a.viewTo||u<=a.viewFrom?(a.view=qo(r,i,u),a.viewFrom=i):(a.viewFrom>i?a.view=qo(r,i,a.viewFrom).concat(a.view):a.viewFromu&&(a.view=a.view.slice(0,ho(r,u)))),a.viewTo=u}o(Ry,"adjustView");function Hm(r){for(var i=r.display.view,u=0,a=0;a=r.display.viewTo||S.to().line0?i.blinker=setInterval(function(){r.hasFocus()||pl(r),i.cursorDiv.style.visibility=(u=!u)?"":"hidden"},r.options.cursorBlinkRate):r.options.cursorBlinkRate<0&&(i.cursorDiv.style.visibility="hidden")}}o(ca,"restartBlink");function vd(r){r.hasFocus()||(r.display.input.focus(),r.state.focused||pa(r))}o(vd,"ensureFocus");function hc(r){r.state.delayingBlurEvent=!0,setTimeout(function(){r.state.delayingBlurEvent&&(r.state.delayingBlurEvent=!1,r.state.focused&&pl(r))},100)}o(hc,"delayBlurEvent");function pa(r,i){r.state.delayingBlurEvent&&!r.state.draggingText&&(r.state.delayingBlurEvent=!1),r.options.readOnly!="nocursor"&&(r.state.focused||(Te(r,"focus",r,i),r.state.focused=!0,Xe(r.display.wrapper,"CodeMirror-focused"),!r.curOp&&r.display.selForContextMenu!=r.doc.sel&&(r.display.input.reset(),C&&setTimeout(function(){return r.display.input.reset(!0)},20)),r.display.input.receivedFocus()),ca(r))}o(pa,"onFocus");function pl(r,i){r.state.delayingBlurEvent||(r.state.focused&&(Te(r,"blur",r,i),r.state.focused=!1,xe(r.display.wrapper,"CodeMirror-focused")),clearInterval(r.display.blinker),setTimeout(function(){r.state.focused||(r.display.shift=!1)},150))}o(pl,"onBlur");function _s(r){for(var i=r.display,u=i.lineDiv.offsetTop,a=0;a.005||M<-.005)&&(ai(p.line,y),Ts(p.line),p.rest))for(var D=0;Dr.display.sizerWidth){var V=Math.ceil(S/ua(r.display));V>r.display.maxLineLength&&(r.display.maxLineLength=V,r.display.maxLine=p.line,r.display.maxLineChanged=!0)}}}}o(_s,"updateHeightsInViewport");function Ts(r){if(r.widgets)for(var i=0;i=y&&(g=ao(i,hn(Me(i,b))-r.wrapper.clientHeight),y=b)}return{from:g,to:Math.max(y,g+1)}}o(dl,"visibleLines");function Iy(r,i){if(!ir(r,"scrollCursorIntoView")){var u=r.display,a=u.sizer.getBoundingClientRect(),p=null;if(i.top+a.top<0?p=!0:i.bottom+a.top>(window.innerHeight||document.documentElement.clientHeight)&&(p=!1),p!=null&&!J){var g=_e("div","\u200B",null,`position: absolute; - top: `+(i.top-u.viewOffset-Ss(r.display))+`px; - height: `+(i.bottom-i.top+mn(r)+u.barHeight)+`px; - left: `+i.left+"px; width: "+Math.max(2,i.right-i.left)+"px;");r.display.lineSpace.appendChild(g),g.scrollIntoView(p),r.display.lineSpace.removeChild(g)}}}o(Iy,"maybeScrollWindow");function Fy(r,i,u,a){a==null&&(a=0);var p;!r.options.lineWrapping&&i==u&&(u=i.sticky=="before"?ue(i.line,i.ch+1,"before"):i,i=i.ch?ue(i.line,i.sticky=="before"?i.ch-1:i.ch,"after"):i);for(var g=0;g<5;g++){var y=!1,S=Vn(r,i),b=!u||u==i?S:Vn(r,u);p={left:Math.min(S.left,b.left),top:Math.min(S.top,b.top)-a,right:Math.max(S.left,b.left),bottom:Math.max(S.bottom,b.bottom)+a};var E=da(r,p),M=r.doc.scrollTop,D=r.doc.scrollLeft;if(E.scrollTop!=null&&(sr(r,E.scrollTop),Math.abs(r.doc.scrollTop-M)>1&&(y=!0)),E.scrollLeft!=null&&(hl(r,E.scrollLeft),Math.abs(r.doc.scrollLeft-D)>1&&(y=!0)),!y)break}return p}o(Fy,"scrollPosIntoView");function By(r,i){var u=da(r,i);u.scrollTop!=null&&sr(r,u.scrollTop),u.scrollLeft!=null&&hl(r,u.scrollLeft)}o(By,"scrollIntoView");function da(r,i){var u=r.display,a=Cs(r.display);i.top<0&&(i.top=0);var p=r.curOp&&r.curOp.scrollTop!=null?r.curOp.scrollTop:u.scroller.scrollTop,g=al(r),y={};i.bottom-i.top>g&&(i.bottom=i.top+g);var S=r.doc.height+zr(u),b=i.topS-a;if(i.topp+g){var M=Math.min(i.top,(E?S:i.bottom)-g);M!=p&&(y.scrollTop=M)}var D=r.options.fixedGutter?0:u.gutters.offsetWidth,V=r.curOp&&r.curOp.scrollLeft!=null?r.curOp.scrollLeft:u.scroller.scrollLeft-D,$=qi(r)-u.gutters.offsetWidth,te=i.right-i.left>$;return te&&(i.right=i.left+$),i.left<10?y.scrollLeft=0:i.left$+V-3&&(y.scrollLeft=i.right+(te?0:10)-$),y}o(da,"calculateScrollPos");function ha(r,i){i!=null&&(mc(r),r.curOp.scrollTop=(r.curOp.scrollTop==null?r.doc.scrollTop:r.curOp.scrollTop)+i)}o(ha,"addToScrollTop");function ks(r){mc(r);var i=r.getCursor();r.curOp.scrollToPos={from:i,to:i,margin:r.options.cursorScrollMargin}}o(ks,"ensureCursorVisible");function qu(r,i,u){(i!=null||u!=null)&&mc(r),i!=null&&(r.curOp.scrollLeft=i),u!=null&&(r.curOp.scrollTop=u)}o(qu,"scrollToCoords");function Um(r,i){mc(r),r.curOp.scrollToPos=i}o(Um,"scrollToRange");function mc(r){var i=r.curOp.scrollToPos;if(i){r.curOp.scrollToPos=null;var u=zu(r,i.from),a=zu(r,i.to);zm(r,u,a,i.margin)}}o(mc,"resolveScrollToPos");function zm(r,i,u,a){var p=da(r,{left:Math.min(i.left,u.left),top:Math.min(i.top,u.top)-a,right:Math.max(i.right,u.right),bottom:Math.max(i.bottom,u.bottom)+a});qu(r,p.scrollLeft,p.scrollTop)}o(zm,"scrollToCoordsRange");function sr(r,i){Math.abs(r.doc.scrollTop-i)<2||(n||wd(r,{top:i}),Zr(r,i,!0),n&&wd(r),go(r,100))}o(sr,"updateScrollTop");function Zr(r,i,u){i=Math.max(0,Math.min(r.display.scroller.scrollHeight-r.display.scroller.clientHeight,i)),!(r.display.scroller.scrollTop==i&&!u)&&(r.doc.scrollTop=i,r.display.scrollbars.setScrollTop(i),r.display.scroller.scrollTop!=i&&(r.display.scroller.scrollTop=i))}o(Zr,"setScrollTop");function hl(r,i,u,a){i=Math.max(0,Math.min(i,r.display.scroller.scrollWidth-r.display.scroller.clientWidth)),!((u?i==r.doc.scrollLeft:Math.abs(r.doc.scrollLeft-i)<2)&&!a)&&(r.doc.scrollLeft=i,$m(r),r.display.scroller.scrollLeft!=i&&(r.display.scroller.scrollLeft=i),r.display.scrollbars.setScrollLeft(i))}o(hl,"setScrollLeft");function Vu(r){var i=r.display,u=i.gutters.offsetWidth,a=Math.round(r.doc.height+zr(r.display));return{clientHeight:i.scroller.clientHeight,viewHeight:i.wrapper.clientHeight,scrollWidth:i.scroller.scrollWidth,clientWidth:i.scroller.clientWidth,viewWidth:i.wrapper.clientWidth,barLeft:r.options.fixedGutter?u:0,docHeight:a,scrollHeight:a+mn(r)+i.barHeight,nativeBarWidth:i.nativeBarWidth,gutterWidth:u}}o(Vu,"measureForScrollbars");var Ns=o(function(r,i,u){this.cm=u;var a=this.vert=_e("div",[_e("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),p=this.horiz=_e("div",[_e("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");a.tabIndex=p.tabIndex=-1,r(a),r(p),H(a,"scroll",function(){a.clientHeight&&i(a.scrollTop,"vertical")}),H(p,"scroll",function(){p.clientWidth&&i(p.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,c&&v<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")},"NativeScrollbars");Ns.prototype.update=function(r){var i=r.scrollWidth>r.clientWidth+1,u=r.scrollHeight>r.clientHeight+1,a=r.nativeBarWidth;if(u){this.vert.style.display="block",this.vert.style.bottom=i?a+"px":"0";var p=r.viewHeight-(i?a:0);this.vert.firstChild.style.height=Math.max(0,r.scrollHeight-r.clientHeight+p)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(i){this.horiz.style.display="block",this.horiz.style.right=u?a+"px":"0",this.horiz.style.left=r.barLeft+"px";var g=r.viewWidth-r.barLeft-(u?a:0);this.horiz.firstChild.style.width=Math.max(0,r.scrollWidth-r.clientWidth+g)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&r.clientHeight>0&&(a==0&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:u?a:0,bottom:i?a:0}},Ns.prototype.setScrollLeft=function(r){this.horiz.scrollLeft!=r&&(this.horiz.scrollLeft=r),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Ns.prototype.setScrollTop=function(r){this.vert.scrollTop!=r&&(this.vert.scrollTop=r),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Ns.prototype.zeroWidthHack=function(){var r=I&&!X?"12px":"18px";this.horiz.style.height=this.vert.style.width=r,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new Ct,this.disableVert=new Ct},Ns.prototype.enableZeroWidthBar=function(r,i,u){r.style.pointerEvents="auto";function a(){var p=r.getBoundingClientRect(),g=u=="vert"?document.elementFromPoint(p.right-1,(p.top+p.bottom)/2):document.elementFromPoint((p.right+p.left)/2,p.bottom-1);g!=r?r.style.pointerEvents="none":i.set(1e3,a)}o(a,"maybeDisable"),i.set(1e3,a)},Ns.prototype.clear=function(){var r=this.horiz.parentNode;r.removeChild(this.horiz),r.removeChild(this.vert)};var Ku=o(function(){},"NullScrollbars");Ku.prototype.update=function(){return{bottom:0,right:0}},Ku.prototype.setScrollLeft=function(){},Ku.prototype.setScrollTop=function(){},Ku.prototype.clear=function(){};function Ls(r,i){i||(i=Vu(r));var u=r.display.barWidth,a=r.display.barHeight;ma(r,i);for(var p=0;p<4&&u!=r.display.barWidth||a!=r.display.barHeight;p++)u!=r.display.barWidth&&r.options.lineWrapping&&_s(r),ma(r,Vu(r)),u=r.display.barWidth,a=r.display.barHeight}o(Ls,"updateScrollbars");function ma(r,i){var u=r.display,a=u.scrollbars.update(i);u.sizer.style.paddingRight=(u.barWidth=a.right)+"px",u.sizer.style.paddingBottom=(u.barHeight=a.bottom)+"px",u.heightForcer.style.borderBottom=a.bottom+"px solid transparent",a.right&&a.bottom?(u.scrollbarFiller.style.display="block",u.scrollbarFiller.style.height=a.bottom+"px",u.scrollbarFiller.style.width=a.right+"px"):u.scrollbarFiller.style.display="",a.bottom&&r.options.coverGutterNextToScrollbar&&r.options.fixedGutter?(u.gutterFiller.style.display="block",u.gutterFiller.style.height=a.bottom+"px",u.gutterFiller.style.width=i.gutterWidth+"px"):u.gutterFiller.style.display=""}o(ma,"updateScrollbarsInner");var gc={native:Ns,null:Ku};function ml(r){r.display.scrollbars&&(r.display.scrollbars.clear(),r.display.scrollbars.addClass&&xe(r.display.wrapper,r.display.scrollbars.addClass)),r.display.scrollbars=new gc[r.options.scrollbarStyle](function(i){r.display.wrapper.insertBefore(i,r.display.scrollbarFiller),H(i,"mousedown",function(){r.state.focused&&setTimeout(function(){return r.display.input.focus()},0)}),i.setAttribute("cm-not-content","true")},function(i,u){u=="horizontal"?hl(r,i):sr(r,i)},r),r.display.scrollbars.addClass&&Xe(r.display.wrapper,r.display.scrollbars.addClass)}o(ml,"initScrollbars");var Gu=0;function Ki(r){r.curOp={cm:r,viewChanged:!1,startHeight:r.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Gu,markArrays:null},$i(r.curOp)}o(Ki,"startOperation");function mo(r){var i=r.curOp;i&&hd(i,function(u){for(var a=0;a=u.viewTo)||u.maxLineChanged&&i.options.lineWrapping,r.update=r.mustUpdate&&new An(i,r.mustUpdate&&{top:r.scrollTop,ensure:r.scrollToPos},r.forceUpdate)}o(Hy,"endOperation_R1");function Wy(r){r.updatedDisplay=r.mustUpdate&&yd(r.cm,r.update)}o(Wy,"endOperation_W1");function Uy(r){var i=r.cm,u=i.display;r.updatedDisplay&&_s(i),r.barMeasure=Vu(i),u.maxLineChanged&&!i.options.lineWrapping&&(r.adjustWidthTo=Uu(i,u.maxLine,u.maxLine.text.length).left+3,i.display.sizerWidth=r.adjustWidthTo,r.barMeasure.scrollWidth=Math.max(u.scroller.clientWidth,u.sizer.offsetLeft+r.adjustWidthTo+mn(i)+i.display.barWidth),r.maxScrollLeft=Math.max(0,u.sizer.offsetLeft+r.adjustWidthTo-qi(i))),(r.updatedDisplay||r.selectionChanged)&&(r.preparedSelection=u.input.prepareSelection())}o(Uy,"endOperation_R2");function zy(r){var i=r.cm;r.adjustWidthTo!=null&&(i.display.sizer.style.minWidth=r.adjustWidthTo+"px",r.maxScrollLeft=r.display.viewTo)){var u=+new Date+r.options.workTime,a=$o(r,i.highlightFrontier),p=[];i.iter(a.line,Math.min(i.first+i.size,r.display.viewTo+500),function(g){if(a.line>=r.display.viewFrom){var y=g.styles,S=g.text.length>r.options.maxHighlightLength?Uo(i.mode,a.state):null,b=tc(r,g,a,!0);S&&(a.state=S),g.styles=b.styles;var E=g.styleClasses,M=b.classes;M?g.styleClasses=M:E&&(g.styleClasses=null);for(var D=!y||y.length!=g.styles.length||E!=M&&(!E||!M||E.bgClass!=M.bgClass||E.textClass!=M.textClass),V=0;!D&&Vu)return go(r,r.options.workDelay),!0}),i.highlightFrontier=a.line,i.modeFrontier=Math.max(i.modeFrontier,a.line),p.length&&Jr(r,function(){for(var g=0;g=u.viewFrom&&i.visible.to<=u.viewTo&&(u.updateLineNumbers==null||u.updateLineNumbers>=u.viewTo)&&u.renderedView==u.view&&Hm(r)==0)return!1;vo(r)&&(Xo(r),i.dims=Kn(r));var p=a.first+a.size,g=Math.max(i.visible.from-r.options.viewportMargin,a.first),y=Math.min(p,i.visible.to+r.options.viewportMargin);u.viewFromy&&u.viewTo-y<20&&(y=Math.min(p,u.viewTo)),_i&&(g=jo(r.doc,g),y=pd(r.doc,y));var S=g!=u.viewFrom||y!=u.viewTo||u.lastWrapHeight!=i.wrapperHeight||u.lastWrapWidth!=i.wrapperWidth;Ry(r,g,y),u.viewOffset=hn(Me(r.doc,u.viewFrom)),r.display.mover.style.top=u.viewOffset+"px";var b=Hm(r);if(!S&&b==0&&!i.force&&u.renderedView==u.view&&(u.updateLineNumbers==null||u.updateLineNumbers>=u.viewTo))return!1;var E=jy(r);return b>4&&(u.lineDiv.style.display="none"),Vy(r,u.updateLineNumbers,i.dims),b>4&&(u.lineDiv.style.display=""),u.renderedView=u.view,qy(E),Ve(u.cursorDiv),Ve(u.selectionDiv),u.gutters.style.height=u.sizer.style.minHeight=0,S&&(u.lastWrapHeight=i.wrapperHeight,u.lastWrapWidth=i.wrapperWidth,go(r,400)),u.updateLineNumbers=null,!0}o(yd,"updateDisplayIfNeeded");function Ps(r,i){for(var u=i.viewport,a=!0;;a=!1){if(!a||!r.options.lineWrapping||i.oldDisplayWidth==qi(r)){if(u&&u.top!=null&&(u={top:Math.min(r.doc.height+zr(r.display)-al(r),u.top)}),i.visible=dl(r.display,r.doc,u),i.visible.from>=r.display.viewFrom&&i.visible.to<=r.display.viewTo)break}else a&&(i.visible=dl(r.display,r.doc,u));if(!yd(r,i))break;_s(r);var p=Vu(r);$u(r),Ls(r,p),Sd(r,p),i.force=!1}i.signal(r,"update",r),(r.display.viewFrom!=r.display.reportedViewFrom||r.display.viewTo!=r.display.reportedViewTo)&&(i.signal(r,"viewportChange",r,r.display.viewFrom,r.display.viewTo),r.display.reportedViewFrom=r.display.viewFrom,r.display.reportedViewTo=r.display.viewTo)}o(Ps,"postUpdateDisplay");function wd(r,i){var u=new An(r,i);if(yd(r,u)){_s(r),Ps(r,u);var a=Vu(r);$u(r),Ls(r,a),Sd(r,a),u.finish()}}o(wd,"updateDisplaySimple");function Vy(r,i,u){var a=r.display,p=r.options.lineNumbers,g=a.lineDiv,y=g.firstChild;function S(te){var oe=te.nextSibling;return C&&I&&r.display.currentWheelTarget==te?te.style.display="none":te.parentNode.removeChild(te),oe}o(S,"rm");for(var b=a.view,E=a.viewFrom,M=0;M-1&&($=!1),Du(r,D,E,u)),$&&(Ve(D.lineNumber),D.lineNumber.appendChild(document.createTextNode(jl(r.options,E)))),y=D.node.nextSibling}E+=D.size}for(;y;)y=S(y)}o(Vy,"patchDisplay");function xd(r){var i=r.gutters.offsetWidth;r.sizer.style.marginLeft=i+"px",yr(r,"gutterChanged",r)}o(xd,"updateGutterSpace");function Sd(r,i){r.display.sizer.style.minHeight=i.docHeight+"px",r.display.heightForcer.style.top=i.docHeight+"px",r.display.gutters.style.height=i.docHeight+r.display.barHeight+mn(r)+"px"}o(Sd,"setDocumentHeight");function $m(r){var i=r.display,u=i.view;if(!(!i.alignWidgets&&(!i.gutters.firstChild||!r.options.fixedGutter))){for(var a=fa(i)-i.scroller.scrollLeft+r.doc.scrollLeft,p=i.gutters.offsetWidth,g=a+"px",y=0;yy.clientWidth,b=y.scrollHeight>y.clientHeight;if(!!(a&&S||p&&b)){if(p&&I&&C){e:for(var E=i.target,M=g.view;E!=y;E=E.parentNode)for(var D=0;D=0&&ze(r,a.to())<=0)return u}return-1};var wt=o(function(r,i){this.anchor=r,this.head=i},"Range");wt.prototype.from=function(){return il(this.anchor,this.head)},wt.prototype.to=function(){return gs(this.anchor,this.head)},wt.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch};function tn(r,i,u){var a=r&&r.options.selectionsMayTouch,p=i[u];i.sort(function(V,$){return ze(V.from(),$.from())}),u=ut(i,p);for(var g=1;g0:b>=0){var E=il(S.from(),y.from()),M=gs(S.to(),y.to()),D=S.empty()?y.from()==y.head:S.from()==S.head;g<=u&&--u,i.splice(--g,2,new wt(D?M:E,D?E:M))}}return new pi(i,u)}o(tn,"normalizeSelection");function Os(r,i){return new pi([new wt(r,i||r)],0)}o(Os,"simpleSelection");function Ms(r){return r.text?ue(r.from.line+r.text.length-1,Se(r.text).length+(r.text.length==1?r.from.ch:0)):r.to}o(Ms,"changeEnd");function Ni(r,i){if(ze(r,i.from)<0)return r;if(ze(r,i.to)<=0)return Ms(i);var u=r.line+i.text.length-(i.to.line-i.from.line)-1,a=r.ch;return r.line==i.to.line&&(a+=Ms(i).ch-i.to.ch),ue(u,a)}o(Ni,"adjustForChange");function bd(r,i){for(var u=[],a=0;a1&&r.remove(S.line+1,te-1),r.insert(S.line+1,ge)}yr(r,"change",r,i)}o(wc,"updateDoc");function As(r,i,u){function a(p,g,y){if(p.linked)for(var S=0;S1&&!r.done[r.done.length-2].ranges)return r.done.pop(),Se(r.done)}o(Xy,"lastChangeEvent");function yo(r,i,u,a){var p=r.history;p.undone.length=0;var g=+new Date,y,S;if((p.lastOp==a||p.lastOrigin==i.origin&&i.origin&&(i.origin.charAt(0)=="+"&&p.lastModTime>g-(r.cm?r.cm.options.historyEventDelay:500)||i.origin.charAt(0)=="*"))&&(y=Xy(p,p.lastOp==a)))S=Se(y.changes),ze(i.from,i.to)==0&&ze(i.from,S.to)==0?S.to=Ms(i):y.changes.push(Td(r,i));else{var b=Se(p.done);for((!b||!b.ranges)&&Dn(r.sel,p.done),y={changes:[Td(r,i)],generation:p.generation},p.done.push(y);p.done.length>p.undoDepth;)p.done.shift(),p.done[0].ranges||p.done.shift()}p.done.push(u),p.generation=++p.maxGeneration,p.lastModTime=p.lastSelTime=g,p.lastOp=p.lastSelOp=a,p.lastOrigin=p.lastSelOrigin=i.origin,S||Te(r,"historyAdded")}o(yo,"addChangeToHistory");function Nd(r,i,u,a){var p=i.charAt(0);return p=="*"||p=="+"&&u.ranges.length==a.ranges.length&&u.somethingSelected()==a.somethingSelected()&&new Date-r.history.lastSelTime<=(r.cm?r.cm.options.historyEventDelay:500)}o(Nd,"selectionEventCanBeMerged");function vl(r,i,u,a){var p=r.history,g=a&&a.origin;u==p.lastSelOp||g&&p.lastSelOrigin==g&&(p.lastModTime==p.lastSelTime&&p.lastOrigin==g||Nd(r,g,Se(p.done),i))?p.done[p.done.length-1]=i:Dn(i,p.done),p.lastSelTime=+new Date,p.lastSelOrigin=g,p.lastSelOp=u,a&&a.clearRedo!==!1&&kd(p.undone)}o(vl,"addSelectionToHistory");function Dn(r,i){var u=Se(i);u&&u.ranges&&u.equals(r)||i.push(r)}o(Dn,"pushSelectionToHistory");function Ym(r,i,u,a){var p=i["spans_"+r.id],g=0;r.iter(Math.max(r.first,u),Math.min(r.first+r.size,a),function(y){y.markedSpans&&((p||(p=i["spans_"+r.id]={}))[g]=y.markedSpans),++g})}o(Ym,"attachLocalSpans");function Xm(r){if(!r)return null;for(var i,u=0;u-1&&(Se(S)[D]=E[D],delete E[D])}}return a}o(di,"copyHistoryArray");function Sc(r,i,u,a){if(a){var p=r.anchor;if(u){var g=ze(i,p)<0;g!=ze(u,p)<0?(p=i,i=u):g!=ze(i,u)<0&&(i=u)}return new wt(p,i)}else return new wt(u||i,i)}o(Sc,"extendRange");function Cc(r,i,u,a,p){p==null&&(p=r.cm&&(r.cm.display.shift||r.extend)),$r(r,new pi([Sc(r.sel.primary(),i,u,p)],0),a)}o(Cc,"extendSelection");function Zu(r,i,u){for(var a=[],p=r.cm&&(r.cm.display.shift||r.extend),g=0;g=i.ch:S.to>i.ch))){if(p&&(Te(b,"beforeCursorEnter"),b.explicitlyCleared))if(g.markedSpans){--y;continue}else break;if(!b.atomic)continue;if(u){var D=b.find(a<0?1:-1),V=void 0;if((a<0?M:E)&&(D=_c(r,D,-a,D&&D.line==i.line?g:null)),D&&D.line==i.line&&(V=ze(D,u))&&(a<0?V<0:V>0))return yl(r,D,i,a,p)}var $=b.find(a<0?-1:1);return(a<0?E:M)&&($=_c(r,$,a,$.line==i.line?g:null)),$?yl(r,$,i,a,p):null}}return i}o(yl,"skipAtomicInner");function jr(r,i,u,a,p){var g=a||1,y=yl(r,i,u,g,p)||!p&&yl(r,i,u,g,!0)||yl(r,i,u,-g,p)||!p&&yl(r,i,u,-g,!0);return y||(r.cantEdit=!0,ue(r.first,0))}o(jr,"skipAtomic");function _c(r,i,u,a){return u<0&&i.ch==0?i.line>r.first?He(r,ue(i.line-1)):null:u>0&&i.ch==(a||Me(r,i.line)).text.length?i.line=0;--p)Tc(r,{from:a[p].from,to:a[p].to,text:p?[""]:i.text,origin:i.origin});else Tc(r,i)}}o(ya,"makeChange");function Tc(r,i){if(!(i.text.length==1&&i.text[0]==""&&ze(i.from,i.to)==0)){var u=bd(r,i);yo(r,i,u,r.cm?r.cm.curOp.id:NaN),xa(r,i,u,ku(r,i));var a=[];As(r,function(p,g){!g&&ut(a,p.history)==-1&&(tg(p.history,i),a.push(p.history)),xa(p,i,null,ku(p,i))})}}o(Tc,"makeChangeInner");function kc(r,i,u){var a=r.cm&&r.cm.state.suppressEdits;if(!(a&&!u)){for(var p=r.history,g,y=r.sel,S=i=="undo"?p.done:p.undone,b=i=="undo"?p.undone:p.done,E=0;E=0;--$){var te=V($);if(te)return te.v}}}}o(kc,"makeChangeFromHistory");function wa(r,i){if(i!=0&&(r.first+=i,r.sel=new pi(Or(r.sel.ranges,function(p){return new wt(ue(p.anchor.line+i,p.anchor.ch),ue(p.head.line+i,p.head.ch))}),r.sel.primIndex),r.cm)){et(r.cm,r.first,r.first-i,i);for(var u=r.cm.display,a=u.viewFrom;ar.lastLine())){if(i.from.lineg&&(i={from:i.from,to:ue(g,Me(r,g).text.length),text:[i.text[0]],origin:i.origin}),i.removed=Ei(r,i.from,i.to),u||(u=bd(r,i)),r.cm?Qy(r.cm,i,a):wc(r,i,a),hi(r,u,$t),r.cantEdit&&jr(r,ue(r.firstLine(),0))&&(r.cantEdit=!1)}}o(xa,"makeChangeSingleDoc");function Qy(r,i,u){var a=r.doc,p=r.display,g=i.from,y=i.to,S=!1,b=g.line;r.options.lineWrapping||(b=vt(vr(Me(a,g.line))),a.iter(b,y.line+1,function($){if($==p.maxLine)return S=!0,!0})),a.sel.contains(i.from,i.to)>-1&&Ul(r),wc(a,i,u,Bm(r)),r.options.lineWrapping||(a.iter(b,g.line+i.text.length,function($){var te=ws($);te>p.maxLineLength&&(p.maxLine=$,p.maxLineLength=te,p.maxLineChanged=!0,S=!1)}),S&&(r.curOp.updateMaxLine=!0)),rc(a,g.line),go(r,400);var E=i.text.length-(y.line-g.line)-1;i.full?et(r):g.line==y.line&&i.text.length==1&&!_d(r.doc,i)?Es(r,g.line,"text"):et(r,g.line,y.line+1,E);var M=Ft(r,"changes"),D=Ft(r,"change");if(D||M){var V={from:g,to:y,text:i.text,removed:i.removed,origin:i.origin};D&&yr(r,"change",r,V),M&&(r.curOp.changeObjs||(r.curOp.changeObjs=[])).push(V)}r.display.selForContextMenu=null}o(Qy,"makeChangeSingleDocInEditor");function Sa(r,i,u,a,p){var g;a||(a=u),ze(a,u)<0&&(g=[a,u],u=g[0],a=g[1]),typeof i=="string"&&(i=r.splitLines(i)),ya(r,{from:u,to:a,text:i,origin:p})}o(Sa,"replaceRange");function Ca(r,i,u,a){u1||!(this.children[0]instanceof ba))){var S=[];this.collapse(S),this.children=[new ba(S)],this.children[0].parent=this}},collapse:function(r){for(var i=0;i50){for(var y=p.lines.length%25+25,S=y;S10);r.parent.maybeSpill()}},iterN:function(r,i,u){for(var a=0;ar.display.maxLineLength&&(r.display.maxLine=E,r.display.maxLineLength=M,r.display.maxLineChanged=!0)}a!=null&&r&&this.collapsed&&et(r,a,p+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,r&&Ju(r.doc)),r&&yr(r,"markerCleared",r,this,a,p),i&&mo(r),this.parent&&this.parent.clear()}},Rs.prototype.find=function(r,i){r==null&&this.type=="bookmark"&&(r=1);for(var u,a,p=0;p0||y==0&&g.clearWhenEmpty!==!1)return g;if(g.replacedWith&&(g.collapsed=!0,g.widgetNode=St("span",[g.replacedWith],"CodeMirror-widget"),a.handleMouseEvents||g.widgetNode.setAttribute("cm-ignore-events","true"),a.insertLeft&&(g.widgetNode.insertLeft=!0)),g.collapsed){if(sl(r,i.line,i,u,g)||i.line!=u.line&&sl(r,u.line,i,u,g))throw new Error("Inserting collapsed marker partially overlapping an existing one");Ql()}g.addToHistory&&yo(r,{from:i,to:u,origin:"markText"},r.sel,NaN);var S=i.line,b=r.cm,E;if(r.iter(S,u.line+1,function(D){b&&g.collapsed&&!b.options.lineWrapping&&vr(D)==b.display.maxLine&&(E=!0),g.collapsed&&S!=i.line&&ai(D,0),oc(D,new co(g,S==i.line?i.ch:null,S==u.line?u.ch:null),r.cm&&r.cm.curOp),++S}),g.collapsed&&r.iter(i.line,u.line+1,function(D){qt(r,D)&&ai(D,0)}),g.clearOnEnter&&H(g,"beforeCursorEnter",function(){return g.clear()}),g.readOnly&&(nc(),(r.history.done.length||r.history.undone.length)&&r.clearHistory()),g.collapsed&&(g.id=++Nc,g.atomic=!0),b){if(E&&(b.curOp.updateMaxLine=!0),g.collapsed)et(b,i.line,u.line+1);else if(g.className||g.startStyle||g.endStyle||g.css||g.attributes||g.title)for(var M=i.line;M<=u.line;M++)Es(b,M,"text");g.atomic&&Ju(b.doc),yr(b,"markerAdded",b,g)}return g}o(Is,"markText");var Ea=o(function(r,i){this.markers=r,this.primary=i;for(var u=0;u=0;b--)ya(this,a[b]);S?bc(this,S):this.cm&&ks(this.cm)}),undo:N(function(){kc(this,"undo")}),redo:N(function(){kc(this,"redo")}),undoSelection:N(function(){kc(this,"undo",!0)}),redoSelection:N(function(){kc(this,"redo",!0)}),setExtending:function(r){this.extend=r},getExtending:function(){return this.extend},historySize:function(){for(var r=this.history,i=0,u=0,a=0;a=r.ch)&&i.push(p.marker.parent||p.marker)}return i},findMarks:function(r,i,u){r=He(this,r),i=He(this,i);var a=[],p=r.line;return this.iter(r.line,i.line+1,function(g){var y=g.markedSpans;if(y)for(var S=0;S=b.to||b.from==null&&p!=r.line||b.from!=null&&p==i.line&&b.from>=i.ch)&&(!u||u(b.marker))&&a.push(b.marker.parent||b.marker)}++p}),a},getAllMarks:function(){var r=[];return this.iter(function(i){var u=i.markedSpans;if(u)for(var a=0;ar)return i=r,!0;r-=g,++u}),He(this,ue(u,i))},indexFromPos:function(r){r=He(this,r);var i=r.ch;if(r.linei&&(i=r.from),r.to!=null&&r.to-1){i.state.draggingText(r),setTimeout(function(){return i.display.input.focus()},20);return}try{var M=r.dataTransfer.getData("Text");if(M){var D;if(i.state.draggingText&&!i.state.draggingText.copy&&(D=i.listSelections()),hi(i.doc,Os(u,u)),D)for(var V=0;V=0;S--)Sa(r.doc,"",a[S].from,a[S].to,"+delete");ks(r)})}o(mi,"deleteNearSelection");function of(r,i,u){var a=Ui(r.text,i+u,u);return a<0||a>r.text.length?null:a}o(of,"moveCharLogically");function Mc(r,i,u){var a=of(r,i.ch,u);return a==null?null:new ue(i.line,a,u<0?"after":"before")}o(Mc,"moveLogically");function _a(r,i,u,a,p){if(r){i.doc.direction=="rtl"&&(p=-p);var g=Mn(u,i.doc.direction);if(g){var y=p<0?Se(g):g[0],S=p<0==(y.level==1),b=S?"after":"before",E;if(y.level>0||i.doc.direction=="rtl"){var M=qn(i,u);E=p<0?u.text.length-1:0;var D=Ti(i,M,E).top;E=pn(function(V){return Ti(i,M,V).top==D},p<0==(y.level==1)?y.from:y.to-1,E),b=="before"&&(E=of(u,E,1))}else E=p<0?y.to:y.from;return new ue(a,E,b)}}return new ue(a,p<0?u.text.length:0,p<0?"before":"after")}o(_a,"endOfLine");function ug(r,i,u,a){var p=Mn(i,r.doc.direction);if(!p)return Mc(i,u,a);u.ch>=i.text.length?(u.ch=i.text.length,u.sticky="before"):u.ch<=0&&(u.ch=0,u.sticky="after");var g=Ci(p,u.ch,u.sticky),y=p[g];if(r.doc.direction=="ltr"&&y.level%2==0&&(a>0?y.to>u.ch:y.from=y.from&&V>=M.begin)){var $=D?"before":"after";return new ue(u.line,V,$)}}var te=o(function(ge,be,ve){for(var Ne=o(function(Tt,br){return br?new ue(u.line,S(Tt,1),"before"):new ue(u.line,Tt,"after")},"getRes");ge>=0&&ge0==(Ie.level!=1),it=De?ve.begin:S(ve.end,-1);if(Ie.from<=it&&it0?M.end:S(M.begin,-1);return de!=null&&!(a>0&&de==i.text.length)&&(oe=te(a>0?0:p.length-1,a,E(de)),oe)?oe:null}o(ug,"moveVisually");var xl={selectAll:Zm,singleSelection:function(r){return r.setSelection(r.getCursor("anchor"),r.getCursor("head"),$t)},killLine:function(r){return mi(r,function(i){if(i.empty()){var u=Me(r.doc,i.head.line).text.length;return i.head.ch==u&&i.head.line0)p=new ue(p.line,p.ch+1),r.replaceRange(g.charAt(p.ch-1)+g.charAt(p.ch-2),ue(p.line,p.ch-2),p,"+transpose");else if(p.line>r.doc.first){var y=Me(r.doc,p.line-1).text;y&&(p=new ue(p.line,1),r.replaceRange(g.charAt(0)+r.doc.lineSeparator()+y.charAt(y.length-1),ue(p.line-1,y.length-1),p,"+transpose"))}}u.push(new wt(p,p))}r.setSelections(u)})},newlineAndIndent:function(r){return Jr(r,function(){for(var i=r.listSelections(),u=i.length-1;u>=0;u--)r.replaceRange(r.doc.lineSeparator(),i[u].anchor,i[u].head,"+input");i=r.listSelections();for(var a=0;ar&&ze(i,this.pos)==0&&u==this.button};var qr,Gn;function iw(r,i){var u=+new Date;return Gn&&Gn.compare(u,r,i)?(qr=Gn=null,"triple"):qr&&qr.compare(u,r,i)?(Gn=new Rc(u,r,i),qr=null,"double"):(qr=new Rc(u,r,i),Gn=null,"single")}o(iw,"clickRepeat");function hg(r){var i=this,u=i.display;if(!(ir(i,r)||u.activeTouch&&u.input.supportsTouch())){if(u.input.ensurePolled(),u.shift=r.shiftKey,ji(u,r)){C||(u.scroller.draggable=!1,setTimeout(function(){return u.scroller.draggable=!0},100));return}if(!zd(i,r)){var a=po(i,r),p=el(r),g=a?iw(a,p):"single";window.focus(),p==1&&i.state.selectingText&&i.state.selectingText(r),!(a&&Ic(i,p,a,g,r))&&(p==1?a?mg(i,a,g,r):bi(r)==u.scroller&&or(r):p==2?(a&&Cc(i.doc,a),setTimeout(function(){return u.input.focus()},20)):p==3&&(pe?i.display.input.onContextMenu(r):hc(i)))}}}o(hg,"onMouseDown");function Ic(r,i,u,a,p){var g="Click";return a=="double"?g="Double"+g:a=="triple"&&(g="Triple"+g),g=(i==1?"Left":i==2?"Middle":"Right")+g,Ta(r,Rd(g,p),p,function(y){if(typeof y=="string"&&(y=xl[y]),!y)return!1;var S=!1;try{r.isReadOnly()&&(r.state.suppressEdits=!0),S=y(r,u)!=zt}finally{r.state.suppressEdits=!1}return S})}o(Ic,"handleMappedButton");function ka(r,i,u){var a=r.getOption("configureMouse"),p=a?a(r,i,u):{};if(p.unit==null){var g=G?u.shiftKey&&u.metaKey:u.altKey;p.unit=g?"rectangle":i=="single"?"char":i=="double"?"word":"line"}return(p.extend==null||r.doc.extend)&&(p.extend=r.doc.extend||u.shiftKey),p.addNew==null&&(p.addNew=I?u.metaKey:u.ctrlKey),p.moveOnDrag==null&&(p.moveOnDrag=!(I?u.altKey:u.ctrlKey)),p}o(ka,"configureMouse");function mg(r,i,u,a){c?setTimeout(Hr(vd,r),0):r.curOp.focus=Ge();var p=ka(r,u,a),g=r.doc.sel,y;r.options.dragDrop&&hs&&!r.isReadOnly()&&u=="single"&&(y=g.contains(i))>-1&&(ze((y=g.ranges[y]).from(),i)<0||i.xRel>0)&&(ze(y.to(),i)>0||i.xRel<0)?gg(r,a,i,p):yg(r,a,i,p)}o(mg,"leftButtonDown");function gg(r,i,u,a){var p=r.display,g=!1,y=lr(r,function(E){C&&(p.scroller.draggable=!1),r.state.draggingText=!1,r.state.delayingBlurEvent&&(r.hasFocus()?r.state.delayingBlurEvent=!1:hc(r)),he(p.wrapper.ownerDocument,"mouseup",y),he(p.wrapper.ownerDocument,"mousemove",S),he(p.scroller,"dragstart",b),he(p.scroller,"drop",y),g||(or(E),a.addNew||Cc(r.doc,u,null,null,a.extend),C&&!B||c&&v==9?setTimeout(function(){p.wrapper.ownerDocument.body.focus({preventScroll:!0}),p.input.focus()},20):p.input.focus())}),S=o(function(E){g=g||Math.abs(i.clientX-E.clientX)+Math.abs(i.clientY-E.clientY)>=10},"mouseMove"),b=o(function(){return g=!0},"dragStart");C&&(p.scroller.draggable=!0),r.state.draggingText=y,y.copy=!a.moveOnDrag,H(p.wrapper.ownerDocument,"mouseup",y),H(p.wrapper.ownerDocument,"mousemove",S),H(p.scroller,"dragstart",b),H(p.scroller,"drop",y),r.state.delayingBlurEvent=!0,setTimeout(function(){return p.input.focus()},20),p.scroller.dragDrop&&p.scroller.dragDrop()}o(gg,"leftButtonStartDrag");function vg(r,i,u){if(u=="char")return new wt(i,i);if(u=="word")return r.findWordAt(i);if(u=="line")return new wt(ue(i.line,0),He(r.doc,ue(i.line+1,0)));var a=u(r,i);return new wt(a.from,a.to)}o(vg,"rangeForUnit");function yg(r,i,u,a){c&&hc(r);var p=r.display,g=r.doc;or(i);var y,S,b=g.sel,E=b.ranges;if(a.addNew&&!a.extend?(S=g.sel.contains(u),S>-1?y=E[S]:y=new wt(u,u)):(y=g.sel.primary(),S=g.sel.primIndex),a.unit=="rectangle")a.addNew||(y=new wt(u,u)),u=po(r,i,!0,!0),S=-1;else{var M=vg(r,u,a.unit);a.extend?y=Sc(y,M.anchor,M.head,a.extend):y=M}a.addNew?S==-1?(S=E.length,$r(g,tn(r,E.concat([y]),S),{scroll:!1,origin:"*mouse"})):E.length>1&&E[S].empty()&&a.unit=="char"&&!a.extend?($r(g,tn(r,E.slice(0,S).concat(E.slice(S+1)),0),{scroll:!1,origin:"*mouse"}),b=g.sel):Ld(g,S,y,ie):(S=0,$r(g,new pi([y],0),ie),b=g.sel);var D=u;function V(ve){if(ze(D,ve)!=0)if(D=ve,a.unit=="rectangle"){for(var Ne=[],Ie=r.options.tabSize,De=_t(Me(g,u.line).text,u.ch,Ie),it=_t(Me(g,ve.line).text,ve.ch,Ie),Tt=Math.min(De,it),br=Math.max(De,it),At=Math.min(u.line,ve.line),Sn=Math.min(r.lastLine(),Math.max(u.line,ve.line));At<=Sn;At++){var Cn=Me(g,At).text,dr=Pr(Cn,Tt,Ie);Tt==br?Ne.push(new wt(ue(At,dr),ue(At,dr))):Cn.length>dr&&Ne.push(new wt(ue(At,dr),ue(At,Pr(Cn,br,Ie))))}Ne.length||Ne.push(new wt(u,u)),$r(g,tn(r,b.ranges.slice(0,S).concat(Ne),S),{origin:"*mouse",scroll:!1}),r.scrollIntoView(ve)}else{var Vr=y,Ar=vg(r,ve,a.unit),Lt=Vr.anchor,Bt;ze(Ar.anchor,Lt)>0?(Bt=Ar.head,Lt=il(Vr.from(),Ar.anchor)):(Bt=Ar.anchor,Lt=gs(Vr.to(),Ar.head));var ar=b.ranges.slice(0);ar[S]=Na(r,new wt(He(g,Lt),Bt)),$r(g,tn(r,ar,S),ie)}}o(V,"extendTo");var $=p.wrapper.getBoundingClientRect(),te=0;function oe(ve){var Ne=++te,Ie=po(r,ve,!0,a.unit=="rectangle");if(!!Ie)if(ze(Ie,D)!=0){r.curOp.focus=Ge(),V(Ie);var De=dl(p,g);(Ie.line>=De.to||Ie.line$.bottom?20:0;it&&setTimeout(lr(r,function(){te==Ne&&(p.scroller.scrollTop+=it,oe(ve))}),50)}}o(oe,"extend");function de(ve){r.state.selectingText=!1,te=1/0,ve&&(or(ve),p.input.focus()),he(p.wrapper.ownerDocument,"mousemove",ge),he(p.wrapper.ownerDocument,"mouseup",be),g.history.lastSelOrigin=null}o(de,"done");var ge=lr(r,function(ve){ve.buttons===0||!el(ve)?de(ve):oe(ve)}),be=lr(r,de);r.state.selectingText=be,H(p.wrapper.ownerDocument,"mousemove",ge),H(p.wrapper.ownerDocument,"mouseup",be)}o(yg,"leftButtonSelect");function Na(r,i){var u=i.anchor,a=i.head,p=Me(r.doc,u.line);if(ze(u,a)==0&&u.sticky==a.sticky)return i;var g=Mn(p);if(!g)return i;var y=Ci(g,u.ch,u.sticky),S=g[y];if(S.from!=u.ch&&S.to!=u.ch)return i;var b=y+(S.from==u.ch==(S.level!=1)?0:1);if(b==0||b==g.length)return i;var E;if(a.line!=u.line)E=(a.line-u.line)*(r.doc.direction=="ltr"?1:-1)>0;else{var M=Ci(g,a.ch,a.sticky),D=M-y||(a.ch-u.ch)*(S.level==1?-1:1);M==b-1||M==b?E=D<0:E=D>0}var V=g[b+(E?-1:0)],$=E==(V.level==1),te=$?V.from:V.to,oe=$?"after":"before";return u.ch==te&&u.sticky==oe?i:new wt(new ue(u.line,te,oe),a)}o(Na,"bidiSimplify");function La(r,i,u,a){var p,g;if(i.touches)p=i.touches[0].clientX,g=i.touches[0].clientY;else try{p=i.clientX,g=i.clientY}catch(V){return!1}if(p>=Math.floor(r.display.gutters.getBoundingClientRect().right))return!1;a&&or(i);var y=r.display,S=y.lineDiv.getBoundingClientRect();if(g>S.bottom||!Ft(r,u))return ds(i);g-=S.top-y.viewOffset;for(var b=0;b=p){var M=ao(r.doc,g),D=r.display.gutterSpecs[b];return Te(r,u,r,M,D.className,i),ds(i)}}}o(La,"gutterEvent");function zd(r,i){return La(r,i,"gutterClick",!0)}o(zd,"clickInGutter");function $d(r,i){ji(r.display,i)||wg(r,i)||ir(r,i,"contextmenu")||pe||r.display.input.onContextMenu(i)}o($d,"onContextMenu");function wg(r,i){return Ft(r,"gutterContextMenu")?La(r,i,"gutterContextMenu",!1):!1}o(wg,"contextMenuInGutter");function sf(r){r.display.wrapper.className=r.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+r.options.theme.replace(/(^|\s)\s*/g," cm-s-"),U(r)}o(sf,"themeChanged");var Sl={toString:function(){return"CodeMirror.Init"}},lf={},Pa={};function Fc(r){var i=r.optionHandlers;function u(a,p,g,y){r.defaults[a]=p,g&&(i[a]=y?function(S,b,E){E!=Sl&&g(S,b,E)}:g)}o(u,"option"),r.defineOption=u,r.Init=Sl,u("value","",function(a,p){return a.setValue(p)},!0),u("mode",null,function(a,p){a.doc.modeOption=p,Ed(a)},!0),u("indentUnit",2,Ed,!0),u("indentWithTabs",!1),u("smartIndent",!0),u("tabSize",4,function(a){Xu(a),U(a),et(a)},!0),u("lineSeparator",null,function(a,p){if(a.doc.lineSep=p,!!p){var g=[],y=a.doc.first;a.doc.iter(function(b){for(var E=0;;){var M=b.text.indexOf(p,E);if(M==-1)break;E=M+p.length,g.push(ue(y,M))}y++});for(var S=g.length-1;S>=0;S--)Sa(a.doc,p,g[S],ue(g[S].line,g[S].ch+p.length))}}),u("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g,function(a,p,g){a.state.specialChars=new RegExp(p.source+(p.test(" ")?"":"| "),"g"),g!=Sl&&a.refresh()}),u("specialCharPlaceholder",Ur,function(a){return a.refresh()},!0),u("electricChars",!0),u("inputStyle",A?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),u("spellcheck",!1,function(a,p){return a.getInputField().spellcheck=p},!0),u("autocorrect",!1,function(a,p){return a.getInputField().autocorrect=p},!0),u("autocapitalize",!1,function(a,p){return a.getInputField().autocapitalize=p},!0),u("rtlMoveVisually",!K),u("wholeLineUpdateBefore",!0),u("theme","default",function(a){sf(a),Yu(a)},!0),u("keyMap","default",function(a,p,g){var y=wn(p),S=g!=Sl&&wn(g);S&&S.detach&&S.detach(a,y),y.attach&&y.attach(a,S||null)}),u("extraKeys",null),u("configureMouse",null),u("lineWrapping",!1,xg,!0),u("gutters",[],function(a,p){a.display.gutterSpecs=Cd(p,a.options.lineNumbers),Yu(a)},!0),u("fixedGutter",!0,function(a,p){a.display.gutters.style.left=p?fa(a.display)+"px":"0",a.refresh()},!0),u("coverGutterNextToScrollbar",!1,function(a){return Ls(a)},!0),u("scrollbarStyle","native",function(a){ml(a),Ls(a),a.display.scrollbars.setScrollTop(a.doc.scrollTop),a.display.scrollbars.setScrollLeft(a.doc.scrollLeft)},!0),u("lineNumbers",!1,function(a,p){a.display.gutterSpecs=Cd(a.options.gutters,p),Yu(a)},!0),u("firstLineNumber",1,Yu,!0),u("lineNumberFormatter",function(a){return a},Yu,!0),u("showCursorWhenSelecting",!1,$u,!0),u("resetSelectionOnContextMenu",!0),u("lineWiseCopyCut",!0),u("pasteLinesPerSelection",!0),u("selectionsMayTouch",!1),u("readOnly",!1,function(a,p){p=="nocursor"&&(pl(a),a.display.input.blur()),a.display.input.readOnlyChanged(p)}),u("screenReaderLabel",null,function(a,p){p=p===""?null:p,a.display.input.screenReaderLabelChanged(p)}),u("disableInput",!1,function(a,p){p||a.display.input.reset()},!0),u("dragDrop",!0,ow),u("allowDropFileTypes",null),u("cursorBlinkRate",530),u("cursorScrollMargin",0),u("cursorHeight",1,$u,!0),u("singleCursorHeightPerLine",!0,$u,!0),u("workTime",100),u("workDelay",100),u("flattenSpans",!0,Xu,!0),u("addModeClass",!1,Xu,!0),u("pollInterval",100),u("undoDepth",200,function(a,p){return a.doc.history.undoDepth=p}),u("historyEventDelay",1250),u("viewportMargin",10,function(a){return a.refresh()},!0),u("maxHighlightLength",1e4,Xu,!0),u("moveInputWithCursor",!0,function(a,p){p||a.display.input.resetPosition()}),u("tabindex",null,function(a,p){return a.display.input.getField().tabIndex=p||""}),u("autofocus",null),u("direction","ltr",function(a,p){return a.doc.setDirection(p)},!0),u("phrases",null)}o(Fc,"defineOptions");function ow(r,i,u){var a=u&&u!=Sl;if(!i!=!a){var p=r.display.dragFunctions,g=i?H:he;g(r.display.scroller,"dragstart",p.start),g(r.display.scroller,"dragenter",p.enter),g(r.display.scroller,"dragover",p.over),g(r.display.scroller,"dragleave",p.leave),g(r.display.scroller,"drop",p.drop)}}o(ow,"dragDropChanged");function xg(r){r.options.lineWrapping?(Xe(r.display.wrapper,"CodeMirror-wrap"),r.display.sizer.style.minWidth="",r.display.sizerWidth=null):(xe(r.display.wrapper,"CodeMirror-wrap"),zi(r)),bs(r),et(r),U(r),setTimeout(function(){return Ls(r)},100)}o(xg,"wrappingChanged");function Mt(r,i){var u=this;if(!(this instanceof Mt))return new Mt(r,i);this.options=i=i?Zt(i):{},Zt(lf,i,!1);var a=i.value;typeof a=="string"?a=new yn(a,i.mode,null,i.lineSeparator,i.direction):i.mode&&(a.modeOption=i.mode),this.doc=a;var p=new Mt.inputStyles[i.inputStyle](this),g=this.display=new Ky(r,a,p,i);g.wrapper.CodeMirror=this,sf(this),i.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),ml(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new Ct,keySeq:null,specialChars:null},i.autofocus&&!A&&g.input.focus(),c&&v<11&&setTimeout(function(){return u.display.input.reset(!0)},20),Sg(this),Dd(),Ki(this),this.curOp.forceUpdate=!0,Gm(this,a),i.autofocus&&!A||this.hasFocus()?setTimeout(function(){u.hasFocus()&&!u.state.focused&&pa(u)},20):pl(this);for(var y in Pa)Pa.hasOwnProperty(y)&&Pa[y](this,i[y],Sl);vo(this),i.finishInit&&i.finishInit(this);for(var S=0;S20*20}o(y,"farAway"),H(i.scroller,"touchstart",function(b){if(!ir(r,b)&&!g(b)&&!zd(r,b)){i.input.ensurePolled(),clearTimeout(u);var E=+new Date;i.activeTouch={start:E,moved:!1,prev:E-a.end<=300?a:null},b.touches.length==1&&(i.activeTouch.left=b.touches[0].pageX,i.activeTouch.top=b.touches[0].pageY)}}),H(i.scroller,"touchmove",function(){i.activeTouch&&(i.activeTouch.moved=!0)}),H(i.scroller,"touchend",function(b){var E=i.activeTouch;if(E&&!ji(i,b)&&E.left!=null&&!E.moved&&new Date-E.start<300){var M=r.coordsChar(i.activeTouch,"page"),D;!E.prev||y(E,E.prev)?D=new wt(M,M):!E.prev.prev||y(E,E.prev.prev)?D=r.findWordAt(M):D=new wt(ue(M.line,0),He(r.doc,ue(M.line+1,0))),r.setSelection(D.anchor,D.head),r.focus(),or(b)}p()}),H(i.scroller,"touchcancel",p),H(i.scroller,"scroll",function(){i.scroller.clientHeight&&(sr(r,i.scroller.scrollTop),hl(r,i.scroller.scrollLeft,!0),Te(r,"scroll",r))}),H(i.scroller,"mousewheel",function(b){return Vm(r,b)}),H(i.scroller,"DOMMouseScroll",function(b){return Vm(r,b)}),H(i.wrapper,"scroll",function(){return i.wrapper.scrollTop=i.wrapper.scrollLeft=0}),i.dragFunctions={enter:function(b){ir(r,b)||lo(b)},over:function(b){ir(r,b)||(Md(r,b),lo(b))},start:function(b){return Jy(r,b)},drop:lr(r,lg),leave:function(b){ir(r,b)||Ad(r)}};var S=i.input.getField();H(S,"keyup",function(b){return Ud.call(r,b)}),H(S,"keydown",lr(r,fg)),H(S,"keypress",lr(r,pg)),H(S,"focus",function(b){return pa(r,b)}),H(S,"blur",function(b){return pl(r,b)})}o(Sg,"registerEventHandlers");var af=[];Mt.defineInitHook=function(r){return af.push(r)};function uf(r,i,u,a){var p=r.doc,g;u==null&&(u="add"),u=="smart"&&(p.mode.indent?g=$o(r,i).state:u="prev");var y=r.options.tabSize,S=Me(p,i),b=_t(S.text,null,y);S.stateAfter&&(S.stateAfter=null);var E=S.text.match(/^\s*/)[0],M;if(!a&&!/\S/.test(S.text))M=0,u="not";else if(u=="smart"&&(M=p.mode.indent(g,S.text.slice(E.length),S.text),M==zt||M>150)){if(!a)return;u="prev"}u=="prev"?i>p.first?M=_t(Me(p,i-1).text,null,y):M=0:u=="add"?M=b+r.options.indentUnit:u=="subtract"?M=b-r.options.indentUnit:typeof u=="number"&&(M=b+u),M=Math.max(0,M);var D="",V=0;if(r.options.indentWithTabs)for(var $=Math.floor(M/y);$;--$)V+=y,D+=" ";if(Vy,b=rl(i),E=null;if(S&&a.ranges.length>1)if(Pi&&Pi.text.join(` -`)==i){if(a.ranges.length%Pi.text.length==0){E=[];for(var M=0;M=0;V--){var $=a.ranges[V],te=$.from(),oe=$.to();$.empty()&&(u&&u>0?te=ue(te.line,te.ch-u):r.state.overwrite&&!S?oe=ue(oe.line,Math.min(Me(g,oe.line).text.length,oe.ch+Se(b).length)):S&&Pi&&Pi.lineWise&&Pi.text.join(` -`)==b.join(` -`)&&(te=oe=ue(te.line,0)));var de={from:te,to:oe,text:E?E[V%E.length]:b,origin:p||(S?"paste":r.state.cutIncoming>y?"cut":"+input")};ya(r.doc,de),yr(r,"inputRead",r,de)}i&&!S&&Cg(r,i),ks(r),r.curOp.updateInput<2&&(r.curOp.updateInput=D),r.curOp.typing=!0,r.state.pasteIncoming=r.state.cutIncoming=-1}o(Bc,"applyTextInput");function jd(r,i){var u=r.clipboardData&&r.clipboardData.getData("Text");if(u)return r.preventDefault(),!i.isReadOnly()&&!i.options.disableInput&&Jr(i,function(){return Bc(i,u,0,null,"paste")}),!0}o(jd,"handlePaste");function Cg(r,i){if(!(!r.options.electricChars||!r.options.smartIndent))for(var u=r.doc.sel,a=u.ranges.length-1;a>=0;a--){var p=u.ranges[a];if(!(p.head.ch>100||a&&u.ranges[a-1].head.line==p.head.line)){var g=r.getModeAt(p.head),y=!1;if(g.electricChars){for(var S=0;S-1){y=uf(r,p.head.line,"smart");break}}else g.electricInput&&g.electricInput.test(Me(r.doc,p.head.line).text.slice(0,p.head.ch))&&(y=uf(r,p.head.line,"smart"));y&&yr(r,"electricInput",r,p.head.line)}}}o(Cg,"triggerElectric");function qd(r){for(var i=[],u=[],a=0;ag&&(uf(this,S.head.line,a,!0),g=S.head.line,y==this.doc.sel.primIndex&&ks(this));else{var b=S.from(),E=S.to(),M=Math.max(g,b.line);g=Math.min(this.lastLine(),E.line-(E.ch?0:1))+1;for(var D=M;D0&&Ld(this.doc,y,new wt(b,V[y].to()),$t)}}}),getTokenAt:function(a,p){return Kl(this,a,p)},getLineTokens:function(a,p){return Kl(this,ue(a),p,!0)},getTokenTypeAt:function(a){a=He(this.doc,a);var p=_u(this,Me(this.doc,a.line)),g=0,y=(p.length-1)/2,S=a.ch,b;if(S==0)b=p[2];else for(;;){var E=g+y>>1;if((E?p[E*2-1]:0)>=S)y=E;else if(p[E*2+1]b&&(a=b,y=!0),S=Me(this.doc,a)}else S=a;return ci(this,S,{top:0,left:0},p||"page",g||y).top+(y?this.doc.height-hn(S):0)},defaultTextHeight:function(){return Cs(this.display)},defaultCharWidth:function(){return ua(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(a,p,g,y,S){var b=this.display;a=Vn(this,He(this.doc,a));var E=a.bottom,M=a.left;if(p.style.position="absolute",p.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(p),b.sizer.appendChild(p),y=="over")E=a.top;else if(y=="above"||y=="near"){var D=Math.max(b.wrapper.clientHeight,this.doc.height),V=Math.max(b.sizer.clientWidth,b.lineSpace.clientWidth);(y=="above"||a.bottom+p.offsetHeight>D)&&a.top>p.offsetHeight?E=a.top-p.offsetHeight:a.bottom+p.offsetHeight<=D&&(E=a.bottom),M+p.offsetWidth>V&&(M=V-p.offsetWidth)}p.style.top=E+"px",p.style.left=p.style.right="",S=="right"?(M=b.sizer.clientWidth-p.offsetWidth,p.style.right="0px"):(S=="left"?M=0:S=="middle"&&(M=(b.sizer.clientWidth-p.offsetWidth)/2),p.style.left=M+"px"),g&&By(this,{left:M,top:E,right:M+p.offsetWidth,bottom:E+p.offsetHeight})},triggerOnKeyDown:en(fg),triggerOnKeyPress:en(pg),triggerOnKeyUp:Ud,triggerOnMouseDown:en(hg),execCommand:function(a){if(xl.hasOwnProperty(a))return xl[a].call(null,this)},triggerElectric:en(function(a){Cg(this,a)}),findPosH:function(a,p,g,y){var S=1;p<0&&(S=-1,p=-p);for(var b=He(this.doc,a),E=0;E0&&M(g.charAt(y-1));)--y;for(;S.5||this.options.lineWrapping)&&bs(this),Te(this,"refresh",this)}),swapDoc:en(function(a){var p=this.doc;return p.cm=null,this.state.selectingText&&this.state.selectingText(),Gm(this,a),U(this),this.display.input.reset(),qu(this,a.scrollLeft,a.scrollTop),this.curOp.forceScroll=!0,yr(this,"swapDoc",this,p),p}),phrase:function(a){var p=this.options.phrases;return p&&Object.prototype.hasOwnProperty.call(p,a)?p[a]:a},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Wr(r),r.registerHelper=function(a,p,g){u.hasOwnProperty(a)||(u[a]=r[a]={_global:[]}),u[a][p]=g},r.registerGlobalHelper=function(a,p,g,y){r.registerHelper(a,p,y),u[a]._global.push({pred:g,val:y})}}o(ts,"addEditorMethods");function ff(r,i,u,a,p){var g=i,y=u,S=Me(r,i.line),b=p&&r.direction=="rtl"?-u:u;function E(){var be=i.line+b;return be=r.first+r.size?!1:(i=new ue(be,i.ch,i.sticky),S=Me(r,be))}o(E,"findNextLine");function M(be){var ve;if(a=="codepoint"){var Ne=S.text.charCodeAt(i.ch+(u>0?0:-1));if(isNaN(Ne))ve=null;else{var Ie=u>0?Ne>=55296&&Ne<56320:Ne>=56320&&Ne<57343;ve=new ue(i.line,Math.max(0,Math.min(S.text.length,i.ch+u*(Ie?2:1))),-u)}}else p?ve=ug(r.cm,S,i,u):ve=Mc(S,i,u);if(ve==null)if(!be&&E())i=_a(p,r.cm,S,i.line,b);else return!1;else i=ve;return!0}if(o(M,"moveOnce"),a=="char"||a=="codepoint")M();else if(a=="column")M(!0);else if(a=="word"||a=="group")for(var D=null,V=a=="group",$=r.cm&&r.cm.getHelper(i,"wordChars"),te=!0;!(u<0&&!M(!te));te=!1){var oe=S.text.charAt(i.ch)||` -`,de=gr(oe,$)?"w":V&&oe==` -`?"n":!V||/\s/.test(oe)?null:"p";if(V&&!te&&!de&&(de="s"),D&&D!=de){u<0&&(u=1,M(),i.sticky="after");break}if(de&&(D=de),u>0&&!M(!te))break}var ge=jr(r,i,g,y,!0);return Cu(g,ge)&&(ge.hitSide=!0),ge}o(ff,"findPosH");function Hc(r,i,u,a){var p=r.doc,g=i.left,y;if(a=="page"){var S=Math.min(r.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),b=Math.max(S-.5*Cs(r.display),3);y=(u>0?i.bottom:i.top)+u*b}else a=="line"&&(y=u>0?i.bottom+3:i.top-3);for(var E;E=q(r,g,y),!!E.outside;){if(u<0?y<=0:y>=p.height){E.hitSide=!0;break}y+=u*5}return E}o(Hc,"findPosV");var xt=o(function(r){this.cm=r,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new Ct,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null},"ContentEditableInput");xt.prototype.init=function(r){var i=this,u=this,a=u.cm,p=u.div=r.lineDiv;p.contentEditable=!0,bg(p,a.options.spellcheck,a.options.autocorrect,a.options.autocapitalize);function g(S){for(var b=S.target;b;b=b.parentNode){if(b==p)return!0;if(/\bCodeMirror-(?:line)?widget\b/.test(b.className))break}return!1}o(g,"belongsToInput"),H(p,"paste",function(S){!g(S)||ir(a,S)||jd(S,a)||v<=11&&setTimeout(lr(a,function(){return i.updateFromDOM()}),20)}),H(p,"compositionstart",function(S){i.composing={data:S.data,done:!1}}),H(p,"compositionupdate",function(S){i.composing||(i.composing={data:S.data,done:!1})}),H(p,"compositionend",function(S){i.composing&&(S.data!=i.composing.data&&i.readFromDOMSoon(),i.composing.done=!0)}),H(p,"touchstart",function(){return u.forceCompositionEnd()}),H(p,"input",function(){i.composing||i.readFromDOMSoon()});function y(S){if(!(!g(S)||ir(a,S))){if(a.somethingSelected())Oi({lineWise:!1,text:a.getSelections()}),S.type=="cut"&&a.replaceSelection("",null,"cut");else if(a.options.lineWiseCopyCut){var b=qd(a);Oi({lineWise:!0,text:b.text}),S.type=="cut"&&a.operation(function(){a.setSelections(b.ranges,0,$t),a.replaceSelection("",null,"cut")})}else return;if(S.clipboardData){S.clipboardData.clearData();var E=Pi.text.join(` -`);if(S.clipboardData.setData("Text",E),S.clipboardData.getData("Text")==E){S.preventDefault();return}}var M=Eg(),D=M.firstChild;a.display.lineSpace.insertBefore(M,a.display.lineSpace.firstChild),D.value=Pi.text.join(` -`);var V=Ge();ct(D),setTimeout(function(){a.display.lineSpace.removeChild(M),V.focus(),V==p&&u.showPrimarySelection()},50)}}o(y,"onCopyCut"),H(p,"copy",y),H(p,"cut",y)},xt.prototype.screenReaderLabelChanged=function(r){r?this.div.setAttribute("aria-label",r):this.div.removeAttribute("aria-label")},xt.prototype.prepareSelection=function(){var r=ju(this.cm,!1);return r.focus=Ge()==this.div,r},xt.prototype.showSelection=function(r,i){!r||!this.cm.display.view.length||((r.focus||i)&&this.showPrimarySelection(),this.showMultipleSelections(r))},xt.prototype.getSelection=function(){return this.cm.display.wrapper.ownerDocument.getSelection()},xt.prototype.showPrimarySelection=function(){var r=this.getSelection(),i=this.cm,u=i.doc.sel.primary(),a=u.from(),p=u.to();if(i.display.viewTo==i.display.viewFrom||a.line>=i.display.viewTo||p.line=i.display.viewFrom&&cf(i,a)||{node:S[0].measure.map[2],offset:0},E=p.liner.firstLine()&&(a=ue(a.line-1,Me(r.doc,a.line-1).length)),p.ch==Me(r.doc,p.line).text.length&&p.linei.viewTo-1)return!1;var g,y,S;a.line==i.viewFrom||(g=ho(r,a.line))==0?(y=vt(i.view[0].line),S=i.view[0].node):(y=vt(i.view[g].line),S=i.view[g-1].node.nextSibling);var b=ho(r,p.line),E,M;if(b==i.view.length-1?(E=i.viewTo-1,M=i.lineDiv.lastChild):(E=vt(i.view[b+1].line)-1,M=i.view[b+1].node.previousSibling),!S)return!1;for(var D=r.doc.splitLines(Wc(r,S,M,y,E)),V=Ei(r.doc,ue(y,0),ue(E,Me(r.doc,E).text.length));D.length>1&&V.length>1;)if(Se(D)==Se(V))D.pop(),V.pop(),E--;else if(D[0]==V[0])D.shift(),V.shift(),y++;else break;for(var $=0,te=0,oe=D[0],de=V[0],ge=Math.min(oe.length,de.length);$a.ch&&be.charCodeAt(be.length-te-1)==ve.charCodeAt(ve.length-te-1);)$--,te++;D[D.length-1]=be.slice(0,be.length-te).replace(/^\u200b+/,""),D[0]=D[0].slice($).replace(/\u200b+$/,"");var Ie=ue(y,$),De=ue(E,V.length?Se(V).length-te:0);if(D.length>1||D[0]||ze(Ie,De))return Sa(r.doc,D,Ie,De,"+input"),!0},xt.prototype.ensurePolled=function(){this.forceCompositionEnd()},xt.prototype.reset=function(){this.forceCompositionEnd()},xt.prototype.forceCompositionEnd=function(){!this.composing||(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},xt.prototype.readFromDOMSoon=function(){var r=this;this.readDOMTimeout==null&&(this.readDOMTimeout=setTimeout(function(){if(r.readDOMTimeout=null,r.composing)if(r.composing.done)r.composing=null;else return;r.updateFromDOM()},80))},xt.prototype.updateFromDOM=function(){var r=this;(this.cm.isReadOnly()||!this.pollContent())&&Jr(this.cm,function(){return et(r.cm)})},xt.prototype.setUneditable=function(r){r.contentEditable="false"},xt.prototype.onKeyPress=function(r){r.charCode==0||this.composing||(r.preventDefault(),this.cm.isReadOnly()||lr(this.cm,Bc)(this.cm,String.fromCharCode(r.charCode==null?r.keyCode:r.charCode),0))},xt.prototype.readOnlyChanged=function(r){this.div.contentEditable=String(r!="nocursor")},xt.prototype.onContextMenu=function(){},xt.prototype.resetPosition=function(){},xt.prototype.needsContentAttribute=!0;function cf(r,i){var u=la(r,i.line);if(!u||u.hidden)return null;var a=Me(r.doc,i.line),p=Wu(u,a,i.line),g=Mn(a,r.doc.direction),y="left";if(g){var S=Ci(g,i.ch);y=S%2?"right":"left"}var b=aa(p.map,i.ch,y);return b.offset=b.collapse=="right"?b.end:b.start,b}o(cf,"posToDOM");function Oa(r){for(var i=r;i;i=i.parentNode)if(/CodeMirror-gutter-wrapper/.test(i.className))return!0;return!1}o(Oa,"isInGutter");function Be(r,i){return i&&(r.bad=!0),r}o(Be,"badPos");function Wc(r,i,u,a,p){var g="",y=!1,S=r.doc.lineSeparator(),b=!1;function E($){return function(te){return te.id==$}}o(E,"recognizeMarker");function M(){y&&(g+=S,b&&(g+=S),y=b=!1)}o(M,"close");function D($){$&&(M(),g+=$)}o(D,"addText");function V($){if($.nodeType==1){var te=$.getAttribute("cm-text");if(te){D(te);return}var oe=$.getAttribute("cm-marker"),de;if(oe){var ge=r.findMarks(ue(a,0),ue(p+1,0),E(+oe));ge.length&&(de=ge[0].find(0))&&D(Ei(r.doc,de.from,de.to).join(S));return}if($.getAttribute("contenteditable")=="false")return;var be=/^(pre|div|p|li|table|br)$/i.test($.nodeName);if(!/^br$/i.test($.nodeName)&&$.textContent.length==0)return;be&&M();for(var ve=0;ve<$.childNodes.length;ve++)V($.childNodes[ve]);/^(pre|p)$/i.test($.nodeName)&&(b=!0),be&&(y=!0)}else $.nodeType==3&&D($.nodeValue.replace(/\u200b/g,"").replace(/\u00a0/g," "))}for(o(V,"walk");V(i),i!=u;)i=i.nextSibling,b=!1;return g}o(Wc,"domTextBetween");function Ma(r,i,u){var a;if(i==r.display.lineDiv){if(a=r.display.lineDiv.childNodes[u],!a)return Be(r.clipPos(ue(r.display.viewTo-1)),!0);i=null,u=0}else for(a=i;;a=a.parentNode){if(!a||a==r.display.lineDiv)return null;if(a.parentNode&&a.parentNode==r.display.lineDiv)break}for(var p=0;p=9&&i.hasSelection&&(i.hasSelection=null),u.poll()}),H(p,"paste",function(y){ir(a,y)||jd(y,a)||(a.state.pasteIncoming=+new Date,u.fastPoll())});function g(y){if(!ir(a,y)){if(a.somethingSelected())Oi({lineWise:!1,text:a.getSelections()});else if(a.options.lineWiseCopyCut){var S=qd(a);Oi({lineWise:!0,text:S.text}),y.type=="cut"?a.setSelections(S.ranges,null,$t):(u.prevInput="",p.value=S.text.join(` -`),ct(p))}else return;y.type=="cut"&&(a.state.cutIncoming=+new Date)}}o(g,"prepareCopyCut"),H(p,"cut",g),H(p,"copy",g),H(r.scroller,"paste",function(y){if(!(ji(r,y)||ir(a,y))){if(!p.dispatchEvent){a.state.pasteIncoming=+new Date,u.focus();return}var S=new Event("paste");S.clipboardData=y.clipboardData,p.dispatchEvent(S)}}),H(r.lineSpace,"selectstart",function(y){ji(r,y)||or(y)}),H(p,"compositionstart",function(){var y=a.getCursor("from");u.composing&&u.composing.range.clear(),u.composing={start:y,range:a.markText(y,a.getCursor("to"),{className:"CodeMirror-composing"})}}),H(p,"compositionend",function(){u.composing&&(u.poll(),u.composing.range.clear(),u.composing=null)})},pr.prototype.createField=function(r){this.wrapper=Eg(),this.textarea=this.wrapper.firstChild},pr.prototype.screenReaderLabelChanged=function(r){r?this.textarea.setAttribute("aria-label",r):this.textarea.removeAttribute("aria-label")},pr.prototype.prepareSelection=function(){var r=this.cm,i=r.display,u=r.doc,a=ju(r);if(r.options.moveInputWithCursor){var p=Vn(r,u.sel.primary().head,"div"),g=i.wrapper.getBoundingClientRect(),y=i.lineDiv.getBoundingClientRect();a.teTop=Math.max(0,Math.min(i.wrapper.clientHeight-10,p.top+y.top-g.top)),a.teLeft=Math.max(0,Math.min(i.wrapper.clientWidth-10,p.left+y.left-g.left))}return a},pr.prototype.showSelection=function(r){var i=this.cm,u=i.display;tt(u.cursorDiv,r.cursors),tt(u.selectionDiv,r.selection),r.teTop!=null&&(this.wrapper.style.top=r.teTop+"px",this.wrapper.style.left=r.teLeft+"px")},pr.prototype.reset=function(r){if(!(this.contextMenuPending||this.composing)){var i=this.cm;if(i.somethingSelected()){this.prevInput="";var u=i.getSelection();this.textarea.value=u,i.state.focused&&ct(this.textarea),c&&v>=9&&(this.hasSelection=u)}else r||(this.prevInput=this.textarea.value="",c&&v>=9&&(this.hasSelection=null))}},pr.prototype.getField=function(){return this.textarea},pr.prototype.supportsTouch=function(){return!1},pr.prototype.focus=function(){if(this.cm.options.readOnly!="nocursor"&&(!A||Ge()!=this.textarea))try{this.textarea.focus()}catch(r){}},pr.prototype.blur=function(){this.textarea.blur()},pr.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},pr.prototype.receivedFocus=function(){this.slowPoll()},pr.prototype.slowPoll=function(){var r=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){r.poll(),r.cm.state.focused&&r.slowPoll()})},pr.prototype.fastPoll=function(){var r=!1,i=this;i.pollingFast=!0;function u(){var a=i.poll();!a&&!r?(r=!0,i.polling.set(60,u)):(i.pollingFast=!1,i.slowPoll())}o(u,"p"),i.polling.set(20,u)},pr.prototype.poll=function(){var r=this,i=this.cm,u=this.textarea,a=this.prevInput;if(this.contextMenuPending||!i.state.focused||od(u)&&!a&&!this.composing||i.isReadOnly()||i.options.disableInput||i.state.keySeq)return!1;var p=u.value;if(p==a&&!i.somethingSelected())return!1;if(c&&v>=9&&this.hasSelection===p||I&&/[\uf700-\uf7ff]/.test(p))return i.display.input.reset(),!1;if(i.doc.sel==i.display.selForContextMenu){var g=p.charCodeAt(0);if(g==8203&&!a&&(a="\u200B"),g==8666)return this.reset(),this.cm.execCommand("undo")}for(var y=0,S=Math.min(a.length,p.length);y1e3||p.indexOf(` -`)>-1?u.value=r.prevInput="":r.prevInput=p,r.composing&&(r.composing.range.clear(),r.composing.range=i.markText(r.composing.start,i.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},pr.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},pr.prototype.onKeyPress=function(){c&&v>=9&&(this.hasSelection=null),this.fastPoll()},pr.prototype.onContextMenu=function(r){var i=this,u=i.cm,a=u.display,p=i.textarea;i.contextMenuPending&&i.contextMenuPending();var g=po(u,r),y=a.scroller.scrollTop;if(!g||j)return;var S=u.options.resetSelectionOnContextMenu;S&&u.doc.sel.contains(g)==-1&&lr(u,$r)(u.doc,Os(g),$t);var b=p.style.cssText,E=i.wrapper.style.cssText,M=i.wrapper.offsetParent.getBoundingClientRect();i.wrapper.style.cssText="position: static",p.style.cssText=`position: absolute; width: 30px; height: 30px; - top: `+(r.clientY-M.top-5)+"px; left: "+(r.clientX-M.left-5)+`px; - z-index: 1000; background: `+(c?"rgba(255, 255, 255, .05)":"transparent")+`; - outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);`;var D;C&&(D=window.scrollY),a.input.focus(),C&&window.scrollTo(null,D),a.input.reset(),u.somethingSelected()||(p.value=i.prevInput=" "),i.contextMenuPending=$,a.selForContextMenu=u.doc.sel,clearTimeout(a.detectingSelectAll);function V(){if(p.selectionStart!=null){var oe=u.somethingSelected(),de="\u200B"+(oe?p.value:"");p.value="\u21DA",p.value=de,i.prevInput=oe?"":"\u200B",p.selectionStart=1,p.selectionEnd=de.length,a.selForContextMenu=u.doc.sel}}o(V,"prepareSelectAllHack");function $(){if(i.contextMenuPending==$&&(i.contextMenuPending=!1,i.wrapper.style.cssText=E,p.style.cssText=b,c&&v<9&&a.scrollbars.setScrollTop(a.scroller.scrollTop=y),p.selectionStart!=null)){(!c||c&&v<9)&&V();var oe=0,de=o(function(){a.selForContextMenu==u.doc.sel&&p.selectionStart==0&&p.selectionEnd>0&&i.prevInput=="\u200B"?lr(u,Zm)(u):oe++<10?a.detectingSelectAll=setTimeout(de,500):(a.selForContextMenu=null,a.input.reset())},"poll");a.detectingSelectAll=setTimeout(de,200)}}if(o($,"rehide"),c&&v>=9&&V(),pe){lo(r);var te=o(function(){he(window,"mouseup",te),setTimeout($,20)},"mouseup");H(window,"mouseup",te)}else setTimeout($,50)},pr.prototype.readOnlyChanged=function(r){r||this.reset(),this.textarea.disabled=r=="nocursor",this.textarea.readOnly=!!r},pr.prototype.setUneditable=function(){},pr.prototype.needsContentAttribute=!1;function Vd(r,i){if(i=i?Zt(i):{},i.value=r.value,!i.tabindex&&r.tabIndex&&(i.tabindex=r.tabIndex),!i.placeholder&&r.placeholder&&(i.placeholder=r.placeholder),i.autofocus==null){var u=Ge();i.autofocus=u==r||r.getAttribute("autofocus")!=null&&u==document.body}function a(){r.value=S.getValue()}o(a,"save");var p;if(r.form&&(H(r.form,"submit",a),!i.leaveSubmitMethodAlone)){var g=r.form;p=g.submit;try{var y=g.submit=function(){a(),g.submit=p,g.submit(),g.submit=y}}catch(b){}}i.finishInit=function(b){b.save=a,b.getTextArea=function(){return r},b.toTextArea=function(){b.toTextArea=isNaN,a(),r.parentNode.removeChild(b.getWrapperElement()),r.style.display="",r.form&&(he(r.form,"submit",a),!i.leaveSubmitMethodAlone&&typeof r.form.submit=="function"&&(r.form.submit=p))}},r.style.display="none";var S=Mt(function(b){return r.parentNode.insertBefore(b,r.nextSibling)},i);return S}o(Vd,"fromTextArea");function _g(r){r.off=he,r.on=H,r.wheelEventPixels=Gy,r.Doc=yn,r.splitLines=rl,r.countColumn=_t,r.findColumn=Pr,r.isWordChar=Jt,r.Pass=zt,r.signal=Te,r.Line=Ce,r.changeEnd=Ms,r.scrollbarModel=gc,r.Pos=ue,r.cmpPos=ze,r.modes=zl,r.mimeModes=ms,r.resolveMode=nl,r.getMode=xu,r.modeExtensions=Wo,r.extendMode=ad,r.copyState=Uo,r.startState=ec,r.innerMode=$l,r.commands=xl,r.keyMap=Jo,r.keyName=Id,r.isModifierKey=Oc,r.lookupKey=es,r.normalizeKeyMap=tw,r.StringStream=jt,r.SharedTextMarker=Ea,r.TextMarker=Rs,r.LineWidget=tf,r.e_preventDefault=or,r.e_stopPropagation=li,r.e_stop=lo,r.addClass=Xe,r.contains=Ke,r.rmClass=xe,r.keyNames=Fs}o(_g,"addLegacyProps"),Fc(Mt),ts(Mt);var xn="iter insert remove copy getEditor constructor".split(" ");for(var Uc in yn.prototype)yn.prototype.hasOwnProperty(Uc)&&ut(xn,Uc)<0&&(Mt.prototype[Uc]=function(r){return function(){return r.apply(this.doc,arguments)}}(yn.prototype[Uc]));return Wr(yn),Mt.inputStyles={textarea:pr,contenteditable:xt},Mt.defineMode=function(r){!Mt.defaults.mode&&r!="null"&&(Mt.defaults.mode=r),ld.apply(this,arguments)},Mt.defineMIME=Jf,Mt.defineMode("null",function(){return{token:function(r){return r.skipToEnd()}}}),Mt.defineMIME("text/plain","null"),Mt.defineExtension=function(r,i){Mt.prototype[r]=i},Mt.defineDocExtension=function(r,i){yn.prototype[r]=i},Mt.fromTextArea=Vd,_g(Mt),Mt.version="5.62.3",Mt})});var pL=Ue((sz,cL)=>{var k3=typeof Element!="undefined",N3=typeof Map=="function",L3=typeof Set=="function",P3=typeof ArrayBuffer=="function"&&!!ArrayBuffer.isView;function sy(e,t){if(e===t)return!0;if(e&&t&&typeof e=="object"&&typeof t=="object"){if(e.constructor!==t.constructor)return!1;var n,l,d;if(Array.isArray(e)){if(n=e.length,n!=t.length)return!1;for(l=n;l--!=0;)if(!sy(e[l],t[l]))return!1;return!0}var h;if(N3&&e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(h=e.entries();!(l=h.next()).done;)if(!t.has(l.value[0]))return!1;for(h=e.entries();!(l=h.next()).done;)if(!sy(l.value[1],t.get(l.value[0])))return!1;return!0}if(L3&&e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;for(h=e.entries();!(l=h.next()).done;)if(!t.has(l.value[0]))return!1;return!0}if(P3&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(t)){if(n=e.length,n!=t.length)return!1;for(l=n;l--!=0;)if(e[l]!==t[l])return!1;return!0}if(e.constructor===RegExp)return e.source===t.source&&e.flags===t.flags;if(e.valueOf!==Object.prototype.valueOf)return e.valueOf()===t.valueOf();if(e.toString!==Object.prototype.toString)return e.toString()===t.toString();if(d=Object.keys(e),n=d.length,n!==Object.keys(t).length)return!1;for(l=n;l--!=0;)if(!Object.prototype.hasOwnProperty.call(t,d[l]))return!1;if(k3&&e instanceof Element)return!1;for(l=n;l--!=0;)if(!((d[l]==="_owner"||d[l]==="__v"||d[l]==="__o")&&e.$$typeof)&&!sy(e[d[l]],t[d[l]]))return!1;return!0}return e!==e&&t!==t}o(sy,"equal");cL.exports=o(function(t,n){try{return sy(t,n)}catch(l){if((l.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw l}},"isEqual")});var _L=Ue((T9,EL)=>{"use strict";var z3="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";EL.exports=z3});var LL=Ue((k9,NL)=>{"use strict";var $3=_L();function TL(){}o(TL,"emptyFunction");function kL(){}o(kL,"emptyFunctionWithReset");kL.resetWarningCache=TL;NL.exports=function(){function e(l,d,h,c,v,C){if(C!==$3){var k=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw k.name="Invariant Violation",k}}o(e,"shim"),e.isRequired=e;function t(){return e}o(t,"getShim");var n={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:kL,resetWarningCache:TL};return n.PropTypes=n,n}});var Cm=Ue((P9,PL)=>{PL.exports=LL()();var N9,L9});var cC=Ue((O9,OL)=>{OL.exports=o(function(t,n,l,d){var h=l?l.call(d,t,n):void 0;if(h!==void 0)return!!h;if(t===n)return!0;if(typeof t!="object"||!t||typeof n!="object"||!n)return!1;var c=Object.keys(t),v=Object.keys(n);if(c.length!==v.length)return!1;for(var C=Object.prototype.hasOwnProperty.bind(n),k=0;k{WL.exports=function(){return typeof Promise=="function"&&Promise.prototype&&Promise.prototype.then}});var du=Ue(qf=>{var dC,q3=[0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706];qf.getSymbolSize=o(function(t){if(!t)throw new Error('"version" cannot be null or undefined');if(t<1||t>40)throw new Error('"version" should be in range from 1 to 40');return t*4+17},"getSymbolSize");qf.getSymbolTotalCodewords=o(function(t){return q3[t]},"getSymbolTotalCodewords");qf.getBCHDigit=function(e){let t=0;for(;e!==0;)t++,e>>>=1;return t};qf.setToSJISFunction=o(function(t){if(typeof t!="function")throw new Error('"toSJISFunc" is not a valid function.');dC=t},"setToSJISFunction");qf.isKanjiModeEnabled=function(){return typeof dC!="undefined"};qf.toSJIS=o(function(t){return dC(t)},"toSJIS")});var gy=Ue(Do=>{Do.L={bit:1};Do.M={bit:0};Do.Q={bit:3};Do.H={bit:2};function V3(e){if(typeof e!="string")throw new Error("Param is not a string");switch(e.toLowerCase()){case"l":case"low":return Do.L;case"m":case"medium":return Do.M;case"q":case"quartile":return Do.Q;case"h":case"high":return Do.H;default:throw new Error("Unknown EC Level: "+e)}}o(V3,"fromString");Do.isValid=o(function(t){return t&&typeof t.bit!="undefined"&&t.bit>=0&&t.bit<4},"isValid");Do.from=o(function(t,n){if(Do.isValid(t))return t;try{return V3(t)}catch(l){return n}},"from")});var jL=Ue((Q9,$L)=>{function zL(){this.buffer=[],this.length=0}o(zL,"BitBuffer");zL.prototype={get:function(e){let t=Math.floor(e/8);return(this.buffer[t]>>>7-e%8&1)==1},put:function(e,t){for(let n=0;n>>t-n-1&1)==1)},getLengthInBits:function(){return this.length},putBit:function(e){let t=Math.floor(this.length/8);this.buffer.length<=t&&this.buffer.push(0),e&&(this.buffer[t]|=128>>>this.length%8),this.length++}};$L.exports=zL});var VL=Ue((Z9,qL)=>{function Tm(e){if(!e||e<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=e,this.data=new Uint8Array(e*e),this.reservedBit=new Uint8Array(e*e)}o(Tm,"BitMatrix");Tm.prototype.set=function(e,t,n,l){let d=e*this.size+t;this.data[d]=n,l&&(this.reservedBit[d]=!0)};Tm.prototype.get=function(e,t){return this.data[e*this.size+t]};Tm.prototype.xor=function(e,t,n){this.data[e*this.size+t]^=n};Tm.prototype.isReserved=function(e,t){return this.reservedBit[e*this.size+t]};qL.exports=Tm});var KL=Ue(vy=>{var K3=du().getSymbolSize;vy.getRowColCoords=o(function(t){if(t===1)return[];let n=Math.floor(t/7)+2,l=K3(t),d=l===145?26:Math.ceil((l-13)/(2*n-2))*2,h=[l-7];for(let c=1;c{var G3=du().getSymbolSize,GL=7;YL.getPositions=o(function(t){let n=G3(t);return[[0,0],[n-GL,0],[0,n-GL]]},"getPositions")});var QL=Ue(rr=>{rr.Patterns={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var Vf={N1:3,N2:3,N3:40,N4:10};rr.isValid=o(function(t){return t!=null&&t!==""&&!isNaN(t)&&t>=0&&t<=7},"isValid");rr.from=o(function(t){return rr.isValid(t)?parseInt(t,10):void 0},"from");rr.getPenaltyN1=o(function(t){let n=t.size,l=0,d=0,h=0,c=null,v=null;for(let C=0;C=5&&(l+=Vf.N1+(d-5)),c=O,d=1),O=t.get(k,C),O===v?h++:(h>=5&&(l+=Vf.N1+(h-5)),v=O,h=1)}d>=5&&(l+=Vf.N1+(d-5)),h>=5&&(l+=Vf.N1+(h-5))}return l},"getPenaltyN1");rr.getPenaltyN2=o(function(t){let n=t.size,l=0;for(let d=0;d=10&&(d===1488||d===93)&&l++,h=h<<1&2047|t.get(v,c),v>=10&&(h===1488||h===93)&&l++}return l*Vf.N3},"getPenaltyN3");rr.getPenaltyN4=o(function(t){let n=0,l=t.data.length;for(let h=0;h{var hu=gy(),yy=[1,1,1,1,1,1,1,1,1,1,2,2,1,2,2,4,1,2,4,4,2,4,4,4,2,4,6,5,2,4,6,6,2,5,8,8,4,5,8,8,4,5,8,11,4,8,10,11,4,9,12,16,4,9,16,16,6,10,12,18,6,10,17,16,6,11,16,19,6,13,18,21,7,14,21,25,8,16,20,25,8,17,23,25,9,17,23,34,9,18,25,30,10,20,27,32,12,21,29,35,12,23,34,37,12,25,34,40,13,26,35,42,14,28,38,45,15,29,40,48,16,31,43,51,17,33,45,54,18,35,48,57,19,37,51,60,19,38,53,63,20,40,56,66,21,43,59,70,22,45,62,74,24,47,65,77,25,49,68,81],wy=[7,10,13,17,10,16,22,28,15,26,36,44,20,36,52,64,26,48,72,88,36,64,96,112,40,72,108,130,48,88,132,156,60,110,160,192,72,130,192,224,80,150,224,264,96,176,260,308,104,198,288,352,120,216,320,384,132,240,360,432,144,280,408,480,168,308,448,532,180,338,504,588,196,364,546,650,224,416,600,700,224,442,644,750,252,476,690,816,270,504,750,900,300,560,810,960,312,588,870,1050,336,644,952,1110,360,700,1020,1200,390,728,1050,1260,420,784,1140,1350,450,812,1200,1440,480,868,1290,1530,510,924,1350,1620,540,980,1440,1710,570,1036,1530,1800,570,1064,1590,1890,600,1120,1680,1980,630,1204,1770,2100,660,1260,1860,2220,720,1316,1950,2310,750,1372,2040,2430];hC.getBlocksCount=o(function(t,n){switch(n){case hu.L:return yy[(t-1)*4+0];case hu.M:return yy[(t-1)*4+1];case hu.Q:return yy[(t-1)*4+2];case hu.H:return yy[(t-1)*4+3];default:return}},"getBlocksCount");hC.getTotalCodewordsCount=o(function(t,n){switch(n){case hu.L:return wy[(t-1)*4+0];case hu.M:return wy[(t-1)*4+1];case hu.Q:return wy[(t-1)*4+2];case hu.H:return wy[(t-1)*4+3];default:return}},"getTotalCodewordsCount")});var ZL=Ue(Sy=>{var km=new Uint8Array(512),xy=new Uint8Array(256);o(function(){let t=1;for(let n=0;n<255;n++)km[n]=t,xy[t]=n,t<<=1,t&256&&(t^=285);for(let n=255;n<512;n++)km[n]=km[n-255]},"initTables")();Sy.log=o(function(t){if(t<1)throw new Error("log("+t+")");return xy[t]},"log");Sy.exp=o(function(t){return km[t]},"exp");Sy.mul=o(function(t,n){return t===0||n===0?0:km[xy[t]+xy[n]]},"mul")});var JL=Ue(Nm=>{var gC=ZL();Nm.mul=o(function(t,n){let l=new Uint8Array(t.length+n.length-1);for(let d=0;d=0;){let d=l[0];for(let c=0;c{var eP=JL();function vC(e){this.genPoly=void 0,this.degree=e,this.degree&&this.initialize(this.degree)}o(vC,"ReedSolomonEncoder");vC.prototype.initialize=o(function(t){this.degree=t,this.genPoly=eP.generateECPolynomial(this.degree)},"initialize");vC.prototype.encode=o(function(t){if(!this.genPoly)throw new Error("Encoder not initialized");let n=new Uint8Array(t.length+this.degree);n.set(t);let l=eP.mod(n,this.genPoly),d=this.degree-l.length;if(d>0){let h=new Uint8Array(this.degree);return h.set(l,d),h}return l},"encode");tP.exports=vC});var yC=Ue(nP=>{nP.isValid=o(function(t){return!isNaN(t)&&t>=1&&t<=40},"isValid")});var wC=Ue(Bl=>{var iP="[0-9]+",X3="[A-Z $%*+\\-./:]+",Lm="(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";Lm=Lm.replace(/u/g,"\\u");var Q3="(?:(?![A-Z0-9 $%*+\\-./:]|"+Lm+`)(?:.|[\r -]))+`;Bl.KANJI=new RegExp(Lm,"g");Bl.BYTE_KANJI=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g");Bl.BYTE=new RegExp(Q3,"g");Bl.NUMERIC=new RegExp(iP,"g");Bl.ALPHANUMERIC=new RegExp(X3,"g");var Z3=new RegExp("^"+Lm+"$"),J3=new RegExp("^"+iP+"$"),eB=new RegExp("^[A-Z0-9 $%*+\\-./:]+$");Bl.testKanji=o(function(t){return Z3.test(t)},"testKanji");Bl.testNumeric=o(function(t){return J3.test(t)},"testNumeric");Bl.testAlphanumeric=o(function(t){return eB.test(t)},"testAlphanumeric")});var mu=Ue(Xr=>{var tB=yC(),xC=wC();Xr.NUMERIC={id:"Numeric",bit:1<<0,ccBits:[10,12,14]};Xr.ALPHANUMERIC={id:"Alphanumeric",bit:1<<1,ccBits:[9,11,13]};Xr.BYTE={id:"Byte",bit:1<<2,ccBits:[8,16,16]};Xr.KANJI={id:"Kanji",bit:1<<3,ccBits:[8,10,12]};Xr.MIXED={bit:-1};Xr.getCharCountIndicator=o(function(t,n){if(!t.ccBits)throw new Error("Invalid mode: "+t);if(!tB.isValid(n))throw new Error("Invalid version: "+n);return n>=1&&n<10?t.ccBits[0]:n<27?t.ccBits[1]:t.ccBits[2]},"getCharCountIndicator");Xr.getBestModeForData=o(function(t){return xC.testNumeric(t)?Xr.NUMERIC:xC.testAlphanumeric(t)?Xr.ALPHANUMERIC:xC.testKanji(t)?Xr.KANJI:Xr.BYTE},"getBestModeForData");Xr.toString=o(function(t){if(t&&t.id)return t.id;throw new Error("Invalid mode")},"toString");Xr.isValid=o(function(t){return t&&t.bit&&t.ccBits},"isValid");function rB(e){if(typeof e!="string")throw new Error("Param is not a string");switch(e.toLowerCase()){case"numeric":return Xr.NUMERIC;case"alphanumeric":return Xr.ALPHANUMERIC;case"kanji":return Xr.KANJI;case"byte":return Xr.BYTE;default:throw new Error("Unknown mode: "+e)}}o(rB,"fromString");Xr.from=o(function(t,n){if(Xr.isValid(t))return t;try{return rB(t)}catch(l){return n}},"from")});var uP=Ue(Kf=>{var Cy=du(),nB=mC(),oP=gy(),gu=mu(),SC=yC(),sP=1<<12|1<<11|1<<10|1<<9|1<<8|1<<5|1<<2|1<<0,lP=Cy.getBCHDigit(sP);function iB(e,t,n){for(let l=1;l<=40;l++)if(t<=Kf.getCapacity(l,n,e))return l}o(iB,"getBestVersionForDataLength");function aP(e,t){return gu.getCharCountIndicator(e,t)+4}o(aP,"getReservedBitsCount");function oB(e,t){let n=0;return e.forEach(function(l){n+=aP(l.mode,t)+l.getBitsLength()}),n}o(oB,"getTotalBitsFromDataArray");function sB(e,t){for(let n=1;n<=40;n++)if(oB(e,n)<=Kf.getCapacity(n,t,gu.MIXED))return n}o(sB,"getBestVersionForMixedData");Kf.from=o(function(t,n){return SC.isValid(t)?parseInt(t,10):n},"from");Kf.getCapacity=o(function(t,n,l){if(!SC.isValid(t))throw new Error("Invalid QR Code version");typeof l=="undefined"&&(l=gu.BYTE);let d=Cy.getSymbolTotalCodewords(t),h=nB.getTotalCodewordsCount(t,n),c=(d-h)*8;if(l===gu.MIXED)return c;let v=c-aP(l,t);switch(l){case gu.NUMERIC:return Math.floor(v/10*3);case gu.ALPHANUMERIC:return Math.floor(v/11*2);case gu.KANJI:return Math.floor(v/13);case gu.BYTE:default:return Math.floor(v/8)}},"getCapacity");Kf.getBestVersionForData=o(function(t,n){let l,d=oP.from(n,oP.M);if(Array.isArray(t)){if(t.length>1)return sB(t,d);if(t.length===0)return 1;l=t[0]}else l=t;return iB(l.mode,l.getLength(),d)},"getBestVersionForData");Kf.getEncodedBits=o(function(t){if(!SC.isValid(t)||t<7)throw new Error("Invalid QR Code version");let n=t<<12;for(;Cy.getBCHDigit(n)-lP>=0;)n^=sP<{var CC=du(),fP=1<<10|1<<8|1<<5|1<<4|1<<2|1<<1|1<<0,lB=1<<14|1<<12|1<<10|1<<4|1<<1,cP=CC.getBCHDigit(fP);pP.getEncodedBits=o(function(t,n){let l=t.bit<<3|n,d=l<<10;for(;CC.getBCHDigit(d)-cP>=0;)d^=fP<{var aB=mu();function Kp(e){this.mode=aB.NUMERIC,this.data=e.toString()}o(Kp,"NumericData");Kp.getBitsLength=o(function(t){return 10*Math.floor(t/3)+(t%3?t%3*3+1:0)},"getBitsLength");Kp.prototype.getLength=o(function(){return this.data.length},"getLength");Kp.prototype.getBitsLength=o(function(){return Kp.getBitsLength(this.data.length)},"getBitsLength");Kp.prototype.write=o(function(t){let n,l,d;for(n=0;n+3<=this.data.length;n+=3)l=this.data.substr(n,3),d=parseInt(l,10),t.put(d,10);let h=this.data.length-n;h>0&&(l=this.data.substr(n),d=parseInt(l,10),t.put(d,h*3+1))},"write");hP.exports=Kp});var vP=Ue((p$,gP)=>{var uB=mu(),bC=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"," ","$","%","*","+","-",".","/",":"];function Gp(e){this.mode=uB.ALPHANUMERIC,this.data=e}o(Gp,"AlphanumericData");Gp.getBitsLength=o(function(t){return 11*Math.floor(t/2)+6*(t%2)},"getBitsLength");Gp.prototype.getLength=o(function(){return this.data.length},"getLength");Gp.prototype.getBitsLength=o(function(){return Gp.getBitsLength(this.data.length)},"getBitsLength");Gp.prototype.write=o(function(t){let n;for(n=0;n+2<=this.data.length;n+=2){let l=bC.indexOf(this.data[n])*45;l+=bC.indexOf(this.data[n+1]),t.put(l,11)}this.data.length%2&&t.put(bC.indexOf(this.data[n]),6)},"write");gP.exports=Gp});var wP=Ue((d$,yP)=>{"use strict";yP.exports=o(function(t){for(var n=[],l=t.length,d=0;d=55296&&h<=56319&&l>d+1){var c=t.charCodeAt(d+1);c>=56320&&c<=57343&&(h=(h-55296)*1024+c-56320+65536,d+=1)}if(h<128){n.push(h);continue}if(h<2048){n.push(h>>6|192),n.push(h&63|128);continue}if(h<55296||h>=57344&&h<65536){n.push(h>>12|224),n.push(h>>6&63|128),n.push(h&63|128);continue}if(h>=65536&&h<=1114111){n.push(h>>18|240),n.push(h>>12&63|128),n.push(h>>6&63|128),n.push(h&63|128);continue}n.push(239,191,189)}return new Uint8Array(n).buffer},"encodeUtf8")});var SP=Ue((h$,xP)=>{var fB=wP(),cB=mu();function Yp(e){this.mode=cB.BYTE,typeof e=="string"&&(e=fB(e)),this.data=new Uint8Array(e)}o(Yp,"ByteData");Yp.getBitsLength=o(function(t){return t*8},"getBitsLength");Yp.prototype.getLength=o(function(){return this.data.length},"getLength");Yp.prototype.getBitsLength=o(function(){return Yp.getBitsLength(this.data.length)},"getBitsLength");Yp.prototype.write=function(e){for(let t=0,n=this.data.length;t{var pB=mu(),dB=du();function Xp(e){this.mode=pB.KANJI,this.data=e}o(Xp,"KanjiData");Xp.getBitsLength=o(function(t){return t*13},"getBitsLength");Xp.prototype.getLength=o(function(){return this.data.length},"getLength");Xp.prototype.getBitsLength=o(function(){return Xp.getBitsLength(this.data.length)},"getBitsLength");Xp.prototype.write=function(e){let t;for(t=0;t=33088&&n<=40956)n-=33088;else if(n>=57408&&n<=60351)n-=49472;else throw new Error("Invalid SJIS character: "+this.data[t]+` -Make sure your charset is UTF-8`);n=(n>>>8&255)*192+(n&255),e.put(n,13)}};CP.exports=Xp});var EP=Ue((g$,EC)=>{"use strict";var Pm={single_source_shortest_paths:function(e,t,n){var l={},d={};d[t]=0;var h=Pm.PriorityQueue.make();h.push(t,0);for(var c,v,C,k,O,j,B,X,J;!h.empty();){c=h.pop(),v=c.value,k=c.cost,O=e[v]||{};for(C in O)O.hasOwnProperty(C)&&(j=O[C],B=k+j,X=d[C],J=typeof d[C]=="undefined",(J||X>B)&&(d[C]=B,h.push(C,B),l[C]=v))}if(typeof n!="undefined"&&typeof d[n]=="undefined"){var Z=["Could not find a path from ",t," to ",n,"."].join("");throw new Error(Z)}return l},extract_shortest_path_from_predecessor_list:function(e,t){for(var n=[],l=t,d;l;)n.push(l),d=e[l],l=e[l];return n.reverse(),n},find_path:function(e,t,n){var l=Pm.single_source_shortest_paths(e,t,n);return Pm.extract_shortest_path_from_predecessor_list(l,n)},PriorityQueue:{make:function(e){var t=Pm.PriorityQueue,n={},l;e=e||{};for(l in t)t.hasOwnProperty(l)&&(n[l]=t[l]);return n.queue=[],n.sorter=e.sorter||t.default_sorter,n},default_sorter:function(e,t){return e.cost-t.cost},push:function(e,t){var n={value:e,cost:t};this.queue.push(n),this.queue.sort(this.sorter)},pop:function(){return this.queue.shift()},empty:function(){return this.queue.length===0}}};typeof EC!="undefined"&&(EC.exports=Pm)});var MP=Ue(Qp=>{var It=mu(),_P=mP(),TP=vP(),kP=SP(),NP=bP(),Om=wC(),by=du(),hB=EP();function LP(e){return unescape(encodeURIComponent(e)).length}o(LP,"getStringByteLength");function Mm(e,t,n){let l=[],d;for(;(d=e.exec(n))!==null;)l.push({data:d[0],index:d.index,mode:t,length:d[0].length});return l}o(Mm,"getSegments");function PP(e){let t=Mm(Om.NUMERIC,It.NUMERIC,e),n=Mm(Om.ALPHANUMERIC,It.ALPHANUMERIC,e),l,d;return by.isKanjiModeEnabled()?(l=Mm(Om.BYTE,It.BYTE,e),d=Mm(Om.KANJI,It.KANJI,e)):(l=Mm(Om.BYTE_KANJI,It.BYTE,e),d=[]),t.concat(n,l,d).sort(function(c,v){return c.index-v.index}).map(function(c){return{data:c.data,mode:c.mode,length:c.length}})}o(PP,"getSegmentsFromString");function _C(e,t){switch(t){case It.NUMERIC:return _P.getBitsLength(e);case It.ALPHANUMERIC:return TP.getBitsLength(e);case It.KANJI:return NP.getBitsLength(e);case It.BYTE:return kP.getBitsLength(e)}}o(_C,"getSegmentBitsLength");function mB(e){return e.reduce(function(t,n){let l=t.length-1>=0?t[t.length-1]:null;return l&&l.mode===n.mode?(t[t.length-1].data+=n.data,t):(t.push(n),t)},[])}o(mB,"mergeSegments");function gB(e){let t=[];for(let n=0;n{var Ey=du(),TC=gy(),yB=jL(),wB=VL(),xB=KL(),SB=XL(),kC=QL(),NC=mC(),CB=rP(),_y=uP(),bB=dP(),EB=mu(),LC=MP();function _B(e,t){let n=e.size,l=SB.getPositions(t);for(let d=0;d=0&&v<=6&&(C===0||C===6)||C>=0&&C<=6&&(v===0||v===6)||v>=2&&v<=4&&C>=2&&C<=4?e.set(h+v,c+C,!0,!0):e.set(h+v,c+C,!1,!0))}}o(_B,"setupFinderPattern");function TB(e){let t=e.size;for(let n=8;n>v&1)==1,e.set(d,h,c,!0),e.set(h,d,c,!0)}o(NB,"setupVersionInfo");function PC(e,t,n){let l=e.size,d=bB.getEncodedBits(t,n),h,c;for(h=0;h<15;h++)c=(d>>h&1)==1,h<6?e.set(h,8,c,!0):h<8?e.set(h+1,8,c,!0):e.set(l-15+h,8,c,!0),h<8?e.set(8,l-h-1,c,!0):h<9?e.set(8,15-h-1+1,c,!0):e.set(8,15-h-1,c,!0);e.set(l-8,8,1,!0)}o(PC,"setupFormatInfo");function LB(e,t){let n=e.size,l=-1,d=n-1,h=7,c=0;for(let v=n-1;v>0;v-=2)for(v===6&&v--;;){for(let C=0;C<2;C++)if(!e.isReserved(d,v-C)){let k=!1;c>>h&1)==1),e.set(d,v-C,k),h--,h===-1&&(c++,h=7)}if(d+=l,d<0||n<=d){d-=l,l=-l;break}}}o(LB,"setupData");function PB(e,t,n){let l=new yB;n.forEach(function(C){l.put(C.mode.bit,4),l.put(C.getLength(),EB.getCharCountIndicator(C.mode,e)),C.write(l)});let d=Ey.getSymbolTotalCodewords(e),h=NC.getTotalCodewordsCount(e,t),c=(d-h)*8;for(l.getLengthInBits()+4<=c&&l.put(0,4);l.getLengthInBits()%8!=0;)l.putBit(0);let v=(c-l.getLengthInBits())/8;for(let C=0;C1}i(Vf,"hasBadZoomedRects");var ac={},vs={};function zp(r,o){arguments.length>2&&(o.dependencies=Array.prototype.slice.call(arguments,2)),ac[r]=o}i(zp,"defineMode");function Up(r,o){vs[r]=o}i(Up,"defineMIME");function La(r){if(typeof r=="string"&&vs.hasOwnProperty(r))r=vs[r];else if(r&&typeof r.name=="string"&&vs.hasOwnProperty(r.name)){var o=vs[r.name];typeof o=="string"&&(o={name:o}),r=io(o,r),r.name=o.name}else{if(typeof r=="string"&&/^[\w\-]+\/[\w\-]+\+xml$/.test(r))return La("application/xml");if(typeof r=="string"&&/^[\w\-]+\/[\w\-]+\+json$/.test(r))return La("application/json")}return typeof r=="string"?{name:r}:r||{name:"null"}}i(La,"resolveMode");function lc(r,o){o=La(o);var c=ac[o.name];if(!c)return lc(r,"text/plain");var u=c(r,o);if(ao.hasOwnProperty(o.name)){var p=ao[o.name];for(var g in p)p.hasOwnProperty(g)&&(u.hasOwnProperty(g)&&(u["_"+g]=u[g]),u[g]=p[g])}if(u.name=o.name,o.helperType&&(u.helperType=o.helperType),o.modeProps)for(var y in o.modeProps)u[y]=o.modeProps[y];return u}i(lc,"getMode");var ao={};function qf(r,o){var c=ao.hasOwnProperty(r)?ao[r]:ao[r]={};Gt(o,c)}i(qf,"extendMode");function Oi(r,o){if(o===!0)return o;if(r.copyState)return r.copyState(o);var c={};for(var u in o){var p=o[u];p instanceof Array&&(p=p.concat([])),c[u]=p}return c}i(Oi,"copyState");function uc(r,o){for(var c;r.innerMode&&(c=r.innerMode(o),!(!c||c.mode==r));)o=c.state,r=c.mode;return c||{mode:r,state:o}}i(uc,"innerMode");function cc(r,o,c){return r.startState?r.startState(o,c):!0}i(cc,"startState");var or=i(function(r,o,c){this.pos=this.start=0,this.string=r,this.tabSize=o||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=c},"StringStream");or.prototype.eol=function(){return this.pos>=this.string.length},or.prototype.sol=function(){return this.pos==this.lineStart},or.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},or.prototype.next=function(){if(this.poso},or.prototype.eatSpace=function(){for(var r=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>r},or.prototype.skipToEnd=function(){this.pos=this.string.length},or.prototype.skipTo=function(r){var o=this.string.indexOf(r,this.pos);if(o>-1)return this.pos=o,!0},or.prototype.backUp=function(r){this.pos-=r},or.prototype.column=function(){return this.lastColumnPos0?null:(g&&o!==!1&&(this.pos+=g[0].length),g)}},or.prototype.current=function(){return this.string.slice(this.start,this.pos)},or.prototype.hideFirstChars=function(r,o){this.lineStart+=r;try{return o()}finally{this.lineStart-=r}},or.prototype.lookAhead=function(r){var o=this.lineOracle;return o&&o.lookAhead(r)},or.prototype.baseToken=function(){var r=this.lineOracle;return r&&r.baseToken(this.pos)};function Pe(r,o){if(o-=r.first,o<0||o>=r.size)throw new Error("There is no line "+(o+r.first)+" in the document.");for(var c=r;!c.lines;)for(var u=0;;++u){var p=c.children[u],g=p.chunkSize();if(o=r.first&&oc?ce(c,Pe(r,c).text.length):jf(o,Pe(r,o.line).text.length)}i(qe,"clipPos");function jf(r,o){var c=r.ch;return c==null||c>o?ce(r.line,o):c<0?ce(r.line,0):r}i(jf,"clipToLen");function Pl(r,o){for(var c=[],u=0;uthis.maxLookAhead&&(this.maxLookAhead=r),o},mi.prototype.baseToken=function(r){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=r;)this.baseTokenPos+=2;var o=this.baseTokens[this.baseTokenPos+1];return{type:o&&o.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-r}},mi.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},mi.fromSaved=function(r,o,c){return o instanceof ws?new mi(r,Oi(r.mode,o.state),c,o.lookAhead):new mi(r,Oi(r.mode,o),c)},mi.prototype.save=function(r){var o=r!==!1?Oi(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new ws(o,this.maxLookAhead):o};function Ll(r,o,c,u){var p=[r.state.modeGen],g={};mc(r,o.text,r.doc.mode,c,function(E,O){return p.push(E,O)},g,u);for(var y=c.state,C=i(function(E){c.baseTokens=p;var O=r.state.overlays[E],F=1,K=0;c.state=!0,mc(r,o.text,O.mode,c,function(V,te){for(var ae=F;KV&&p.splice(F,1,V,p[F+1],de),F+=2,K=Math.min(V,de)}if(te)if(O.opaque)p.splice(ae,F-ae,V,"overlay "+te),F=ae+2;else for(;aer.options.maxHighlightLength&&Oi(r.doc.mode,u.state),g=Ll(r,o,u);p&&(u.state=p),o.stateAfter=u.save(!p),o.styles=g.styles,g.classes?o.styleClasses=g.classes:o.styleClasses&&(o.styleClasses=null),c===r.doc.highlightFrontier&&(r.doc.modeFrontier=Math.max(r.doc.modeFrontier,++r.doc.highlightFrontier))}return o.styles}i(Ml,"getLineStyles");function Ss(r,o,c){var u=r.doc,p=r.display;if(!u.mode.startState)return new mi(u,!0,o);var g=Dl(r,o,c),y=g>u.first&&Pe(u,g-1).stateAfter,C=y?mi.fromSaved(u,y,g):new mi(u,cc(u.mode),g);return u.iter(g,o,function(_){uo(r,_.text,C);var E=C.line;_.stateAfter=E==o-1||E%5==0||E>=p.viewFrom&&Eo.start)return g}throw new Error("Mode "+r.name+" failed to advance stream.")}i(Ks,"readToken");var pc=i(function(r,o,c){this.start=r.start,this.end=r.pos,this.string=r.current(),this.type=o||null,this.state=c},"Token");function Rl(r,o,c,u){var p=r.doc,g=p.mode,y;o=qe(p,o);var C=Pe(p,o.line),_=Ss(r,o.line,c),E=new or(C.text,r.options.tabSize,_),O;for(u&&(O=[]);(u||E.posr.options.maxHighlightLength?(C=!1,y&&uo(r,o,u,O.pos),O.pos=o.length,F=null):F=hc(Ks(c,O,u.state,K),g),K){var V=K[0].name;V&&(F="m-"+(F?V+" "+F:V))}if(!C||E!=F){for(;_y;--C){if(C<=g.first)return g.first;var _=Pe(g,C-1),E=_.stateAfter;if(E&&(!c||C+(E instanceof ws?E.lookAhead:0)<=g.modeFrontier))return C;var O=Ft(_.text,null,r.options.tabSize);(p==null||u>O)&&(p=C-1,u=O)}return p}i(Dl,"findStartLine");function Ra(r,o){if(r.modeFrontier=Math.min(r.modeFrontier,o),!(r.highlightFrontierc;u--){var p=Pe(r,u).stateAfter;if(p&&(!(p instanceof ws)||u+p.lookAhead=o:g.to>o);(u||(u=[])).push(new Il(y,g.from,_?null:g.to))}}return u}i(Vp,"markedSpansBefore");function qp(r,o,c){var u;if(r)for(var p=0;p=o:g.to>o);if(C||g.from==o&&y.type=="bookmark"&&(!c||g.marker.insertLeft)){var _=g.from==null||(y.inclusiveLeft?g.from<=o:g.from0&&C)for(var ke=0;ke0)){var O=[_,1],F=Ve(E.from,C.from),K=Ve(E.to,C.to);(F<0||!y.inclusiveLeft&&!F)&&O.push({from:E.from,to:C.from}),(K>0||!y.inclusiveRight&&!K)&&O.push({from:C.to,to:E.to}),p.splice.apply(p,O),_+=O.length-3}}return p}i(jp,"removeReadOnlyRanges");function Bt(r){var o=r.markedSpans;if(o){for(var c=0;co)&&(!u||Gs(u,g.marker)<0)&&(u=g.marker)}return u}i(Ia,"collapsedSpanAround");function Kp(r,o,c,u,p){var g=Pe(r,o),y=Di&&g.markedSpans;if(y)for(var C=0;C=0&&F<=0||O<=0&&F>=0)&&(O<=0&&(_.marker.inclusiveRight&&p.inclusiveLeft?Ve(E.to,c)>=0:Ve(E.to,c)>0)||O>=0&&(_.marker.inclusiveRight&&p.inclusiveLeft?Ve(E.from,u)<=0:Ve(E.from,u)<0)))return!0}}}i(Kp,"conflictingCollapsedRange");function Rt(r){for(var o;o=Fl(r);)r=o.find(-1,!0).line;return r}i(Rt,"visualLine");function Yf(r){for(var o;o=ve(r);)r=o.find(1,!0).line;return r}i(Yf,"visualLineEnd");function Ys(r){for(var o,c;o=ve(r);)r=o.find(1,!0).line,(c||(c=[])).push(r);return c}i(Ys,"visualLineContinued");function Fa(r,o){var c=Pe(r,o),u=Rt(c);return c==u?o:vt(u)}i(Fa,"visualLineNo");function Uo(r,o){if(o>r.lastLine())return o;var c=Pe(r,o),u;if(!Se(r,c))return o;for(;u=ve(c);)c=u.find(1,!0).line;return vt(c)+1}i(Uo,"visualLineEndNo");function Se(r,o){var c=Di&&o.markedSpans;if(c){for(var u=void 0,p=0;po.maxLineLength&&(o.maxLineLength=p,o.maxLine=u)})}i(Bl,"findMaxLine");var pn=i(function(r,o,c){this.text=r,Ot(this,o),this.height=c?c(this):1},"Line");pn.prototype.lineNo=function(){return vt(this)},zn(pn);function Hl(r,o,c,u){r.text=o,r.stateAfter&&(r.stateAfter=null),r.styles&&(r.styles=null),r.order!=null&&(r.order=null),Bt(r),Ot(r,c);var p=u?u(r):1;p!=r.height&&Ri(r,p)}i(Hl,"updateLine");function Qr(r){r.parent=null,Bt(r)}i(Qr,"cleanUpLine");var zl={},Zn={};function Xf(r,o){if(!r||/^\s*$/.test(r))return null;var c=o.addModeClass?Zn:zl;return c[r]||(c[r]=r.replace(/\S+/g,"cm-$&"))}i(Xf,"interpretTokenStyle");function wc(r,o){var c=Xe("span",null,null,S?"padding-right: .1px":null),u={pre:Xe("pre",[c],"CodeMirror-line"),content:c,col:0,pos:0,cm:r,trailingSpace:!1,splitSpaces:r.getOption("lineWrapping")};o.measure={};for(var p=0;p<=(o.rest?o.rest.length:0);p++){var g=p?o.rest[p-1]:o.line,y=void 0;u.pos=0,u.addToken=Ba,Fp(r.display.measure)&&(y=Me(g,r.doc.direction))&&(u.addToken=$t(u.addToken,y)),u.map=[];var C=o!=r.display.externalMeasured&&vt(g);Sc(g,u,Ml(r,g,C)),g.styleClasses&&(g.styleClasses.bgClass&&(u.bgClass=At(g.styleClasses.bgClass,u.bgClass||"")),g.styleClasses.textClass&&(u.textClass=At(g.styleClasses.textClass,u.textClass||""))),u.map.length==0&&u.map.push(0,0,u.content.appendChild($f(r.display.measure))),p==0?(o.measure.map=u.map,o.measure.cache={}):((o.measure.maps||(o.measure.maps=[])).push(u.map),(o.measure.caches||(o.measure.caches=[])).push({}))}if(S){var _=u.content.lastChild;(/\bcm-tab\b/.test(_.className)||_.querySelector&&_.querySelector(".cm-tab"))&&(u.content.className="cm-tab-wrap-hack")}return Mt(r,"renderLine",r,o.line,u.pre),u.pre.className&&(u.textClass=At(u.pre.className,u.textClass||"")),u}i(wc,"buildLineContent");function jt(r){var o=xe("span","\u2022","cm-invalidchar");return o.title="\\u"+r.charCodeAt(0).toString(16),o.setAttribute("aria-label",o.title),o}i(jt,"defaultSpecialCharPlaceholder");function Ba(r,o,c,u,p,g,y){if(o){var C=r.splitSpaces?Ul(o,r.trailingSpace):o,_=r.cm.state.specialChars,E=!1,O;if(!_.test(o))r.col+=o.length,O=document.createTextNode(C),r.map.push(r.pos,r.pos+o.length,O),d&&v<9&&(E=!0),r.pos+=o.length;else{O=document.createDocumentFragment();for(var F=0;;){_.lastIndex=F;var K=_.exec(o),V=K?K.index-F:o.length-F;if(V){var te=document.createTextNode(C.slice(F,F+V));d&&v<9?O.appendChild(xe("span",[te])):O.appendChild(te),r.map.push(r.pos,r.pos+V,te),r.col+=V,r.pos+=V}if(!K)break;F+=V+1;var ae=void 0;if(K[0]==" "){var de=r.cm.options.tabSize,we=de-r.col%de;ae=O.appendChild(xe("span",Ho(we),"cm-tab")),ae.setAttribute("role","presentation"),ae.setAttribute("cm-text"," "),r.col+=we}else K[0]=="\r"||K[0]==` +`?(ae=O.appendChild(xe("span",K[0]=="\r"?"\u240D":"\u2424","cm-invalidchar")),ae.setAttribute("cm-text",K[0]),r.col+=1):(ae=r.cm.options.specialCharPlaceholder(K[0]),ae.setAttribute("cm-text",K[0]),d&&v<9?O.appendChild(xe("span",[ae])):O.appendChild(ae),r.col+=1);r.map.push(r.pos,r.pos+1,ae),r.pos++}}if(r.trailingSpace=C.charCodeAt(o.length-1)==32,c||u||p||E||g||y){var _e=c||"";u&&(_e+=u),p&&(_e+=p);var ye=xe("span",[O],_e,g);if(y)for(var ke in y)y.hasOwnProperty(ke)&&ke!="style"&&ke!="class"&&ye.setAttribute(ke,y[ke]);return r.content.appendChild(ye)}r.content.appendChild(O)}}i(Ba,"buildToken");function Ul(r,o){if(r.length>1&&!/ /.test(r))return r;for(var c=o,u="",p=0;pE&&F.from<=E));K++);if(F.to>=O)return r(c,u,p,g,y,C,_);r(c,u.slice(0,F.to-E),p,g,null,C,_),g=null,u=u.slice(F.to-E),E=F.to}}}i($t,"buildTokenBadBidi");function Ii(r,o,c,u){var p=!u&&c.widgetNode;p&&r.map.push(r.pos,r.pos+o,p),!u&&r.cm.display.input.needsContentAttribute&&(p||(p=r.content.appendChild(document.createElement("span"))),p.setAttribute("cm-marker",c.id)),p&&(r.cm.display.input.setUneditable(p),r.content.appendChild(p)),r.pos+=o,r.trailingSpace=!1}i(Ii,"buildCollapsedSpan");function Sc(r,o,c){var u=r.markedSpans,p=r.text,g=0;if(!u){for(var y=1;y_||it.collapsed&&Oe.to==_&&Oe.from==_)){if(Oe.to!=null&&Oe.to!=_&&V>Oe.to&&(V=Oe.to,ae=""),it.className&&(te+=" "+it.className),it.css&&(K=(K?K+";":"")+it.css),it.startStyle&&Oe.from==_&&(de+=" "+it.startStyle),it.endStyle&&Oe.to==V&&(ke||(ke=[])).push(it.endStyle,Oe.to),it.title&&((_e||(_e={})).title=it.title),it.attributes)for(var Dt in it.attributes)(_e||(_e={}))[Dt]=it.attributes[Dt];it.collapsed&&(!we||Gs(we.marker,it)<0)&&(we=Oe)}else Oe.from>_&&V>Oe.from&&(V=Oe.from)}if(ke)for(var pr=0;pr=C)break;for(var ar=Math.min(C,V);;){if(O){var Sr=_+O.length;if(!we){var xr=Sr>ar?O.slice(0,ar-_):O;o.addToken(o,xr,F?F+te:te,de,_+xr.length==V?ae:"",K,_e)}if(Sr>=ar){O=O.slice(ar-_),_=ar;break}_=Sr,de=""}O=p.slice(g,g=c[E++]),F=Xf(c[E++],o.cm.options)}}}i(Sc,"insertLineContent");function Qf(r,o,c){this.line=o,this.rest=Ys(o),this.size=this.rest?vt(lt(this.rest))-c+1:1,this.node=this.text=null,this.hidden=Se(r,o)}i(Qf,"LineView");function Qs(r,o,c){for(var u=[],p,g=o;g2&&g.push((_.bottom+E.top)/2-c.top)}}g.push(c.bottom-c.top)}}i(xs,"ensureLineHeights");function td(r,o,c){if(r.line==o)return{map:r.measure.map,cache:r.measure.cache};if(r.rest){for(var u=0;uc)return{map:r.measure.maps[p],cache:r.measure.caches[p],before:!0}}}i(td,"mapFromLineView");function Xp(r,o){o=Rt(o);var c=vt(o),u=r.display.externalMeasured=new Qf(r.doc,o,c);u.lineN=c;var p=u.built=wc(r,u);return u.text=p.pre,tt(r.display.lineMeasure,p.pre),u}i(Xp,"updateExternalMeasurement");function Kl(r,o,c,u){return w(r,Tn(r,o),c,u)}i(Kl,"measureChar");function Gl(r,o){if(o>=r.display.viewFrom&&o=c.lineN&&oo)&&(g=_-C,p=g-1,o>=_&&(y="right")),p!=null){if(u=r[E+2],C==_&&c==(u.insertLeft?"left":"right")&&(y=c),c=="left"&&p==0)for(;E&&r[E-2]==r[E-3]&&r[E-1].insertLeft;)u=r[(E-=3)+2],y="left";if(c=="right"&&p==_-C)for(;E=0&&(c=r[p]).left==c.right;p--);return c}i(W,"getUsefulRect");function mn(r,o,c,u){var p=U(o.map,c,u),g=p.node,y=p.start,C=p.end,_=p.collapse,E;if(g.nodeType==3){for(var O=0;O<4;O++){for(;y&&hi(o.line.text.charAt(p.coverStart+y));)--y;for(;p.coverStart+C0&&(_=u="right");var F;r.options.lineWrapping&&(F=g.getClientRects()).length>1?E=F[u=="right"?F.length-1:0]:E=g.getBoundingClientRect()}if(d&&v<9&&!y&&(!E||!E.left&&!E.right)){var K=g.parentNode.getClientRects()[0];K?E={left:K.left,right:K.left+Cs(r.display),top:K.top,bottom:K.bottom}:E=N}for(var V=E.top-o.rect.top,te=E.bottom-o.rect.top,ae=(V+te)/2,de=o.view.measure.heights,we=0;we=u.text.length?(_=u.text.length,E="before"):_<=0&&(_=0,E="after"),!C)return y(E=="before"?_-1:_,E=="before");function O(te,ae,de){var we=C[ae],_e=we.level==1;return y(de?te-1:te,_e!=de)}i(O,"getBidi");var F=ee(C,_,E),K=Y,V=O(_,F,E=="before");return K!=null&&(V.other=O(_,K,E!="before")),V}i(J,"cursorCoords");function Ae(r,o){var c=0;o=qe(r.doc,o),r.options.lineWrapping||(c=Cs(r.display)*o.ch);var u=Pe(r.doc,o.line),p=vi(u)+ea(r.display);return{left:c,right:c,top:p,bottom:p+u.height}}i(Ae,"estimateCoords");function Je(r,o,c,u,p){var g=ce(r,o,c);return g.xRel=p,u&&(g.outside=u),g}i(Je,"PosWithInfo");function yt(r,o,c){var u=r.doc;if(c+=r.display.viewOffset,c<0)return Je(u.first,0,null,-1,-1);var p=ys(u,c),g=u.first+u.size-1;if(p>g)return Je(u.first+u.size-1,Pe(u,g).text.length,null,1,1);o<0&&(o=0);for(var y=Pe(u,p);;){var C=fw(r,y,p,o,c),_=Ia(y,C.ch+(C.xRel>0||C.outside>0?1:0));if(!_)return C;var E=_.find(1);if(E.line==p)return E;y=Pe(u,p=E.line)}}i(yt,"coordsChar");function Nr(r,o,c,u){u-=Yl(o);var p=o.text.length,g=so(function(y){return w(r,c,y-1).bottom<=u},p,0);return p=so(function(y){return w(r,c,y).top>u},g,p),{begin:g,end:p}}i(Nr,"wrappedLineExtent");function Ht(r,o,c,u){c||(c=Tn(r,o));var p=gn(r,o,w(r,c,u),"line").top;return Nr(r,o,c,p)}i(Ht,"wrappedLineExtentChar");function Nc(r,o,c,u){return r.bottom<=c?!1:r.top>c?!0:(u?r.left:r.right)>o}i(Nc,"boxIsAfter");function fw(r,o,c,u,p){p-=vi(o);var g=Tn(r,o),y=Yl(o),C=0,_=o.text.length,E=!0,O=Me(o,r.doc.direction);if(O){var F=(r.options.lineWrapping?rd:Bi)(r,o,c,g,O,u,p);E=F.level!=1,C=E?F.from:F.to-1,_=E?F.to:F.from-1}var K=null,V=null,te=so(function(Ie){var Oe=w(r,g,Ie);return Oe.top+=y,Oe.bottom+=y,Nc(Oe,u,p,!1)?(Oe.top<=p&&Oe.left<=u&&(K=Ie,V=Oe),!0):!1},C,_),ae,de,we=!1;if(V){var _e=u-V.left=ke.bottom?1:0}return te=Hn(o.text,te,1),Je(c,te,de,we,u-ae)}i(fw,"coordsCharInner");function Bi(r,o,c,u,p,g,y){var C=so(function(F){var K=p[F],V=K.level!=1;return Nc(J(r,ce(c,V?K.to:K.from,V?"before":"after"),"line",o,u),g,y,!0)},0,p.length-1),_=p[C];if(C>0){var E=_.level!=1,O=J(r,ce(c,E?_.from:_.to,E?"after":"before"),"line",o,u);Nc(O,g,y,!0)&&O.top>y&&(_=p[C-1])}return _}i(Bi,"coordsBidiPart");function rd(r,o,c,u,p,g,y){var C=Nr(r,o,u,y),_=C.begin,E=C.end;/\s/.test(o.text.charAt(E-1))&&E--;for(var O=null,F=null,K=0;K=E||V.to<=_)){var te=V.level!=1,ae=w(r,u,te?Math.min(E,V.to)-1:Math.max(_,V.from)).right,de=aede)&&(O=V,F=de)}}return O||(O=p[p.length-1]),O.from<_&&(O={from:_,to:O.to,level:O.level}),O.to>E&&(O={from:O.from,to:E,level:O.level}),O}i(rd,"coordsBidiPartWrapped");var za;function po(r){if(r.cachedTextHeight!=null)return r.cachedTextHeight;if(za==null){za=xe("pre",null,"CodeMirror-line-like");for(var o=0;o<49;++o)za.appendChild(document.createTextNode("x")),za.appendChild(xe("br"));za.appendChild(document.createTextNode("x"))}tt(r.measure,za);var c=za.offsetHeight/50;return c>3&&(r.cachedTextHeight=c),Ye(r.measure),c||1}i(po,"textHeight");function Cs(r){if(r.cachedCharWidth!=null)return r.cachedCharWidth;var o=xe("span","xxxxxxxxxx"),c=xe("pre",[o],"CodeMirror-line-like");tt(r.measure,c);var u=o.getBoundingClientRect(),p=(u.right-u.left)/10;return p>2&&(r.cachedCharWidth=p),p||10}i(Cs,"charWidth");function Xl(r){for(var o=r.display,c={},u={},p=o.gutters.clientLeft,g=o.gutters.firstChild,y=0;g;g=g.nextSibling,++y){var C=r.display.gutterSpecs[y].className;c[C]=g.offsetLeft+g.clientLeft+p,u[C]=g.clientWidth}return{fixedPos:kt(o),gutterTotalWidth:o.gutters.offsetWidth,gutterLeft:c,gutterWidth:u,wrapperWidth:o.wrapper.clientWidth}}i(Xl,"getDimensions");function kt(r){return r.scroller.getBoundingClientRect().left-r.sizer.getBoundingClientRect().left}i(kt,"compensateForHScroll");function hg(r){var o=po(r.display),c=r.options.lineWrapping,u=c&&Math.max(5,r.display.scroller.clientWidth/Cs(r.display)-3);return function(p){if(Se(r.doc,p))return 0;var g=0;if(p.widgets)for(var y=0;y0&&(E=Pe(r.doc,_.line).text).length==_.ch){var O=Ft(E,E.length,r.options.tabSize)-E.length;_=ce(_.line,Math.max(0,Math.round((g-Tc(r.display).left)/Cs(r.display))-O))}return _}i(jo,"posFromMouse");function Ua(r,o){if(o>=r.display.viewTo||(o-=r.display.viewFrom,o<0))return null;for(var c=r.display.view,u=0;uo)&&(p.updateLineNumbers=o),r.curOp.viewChanged=!0,o>=p.viewTo)Di&&Fa(r.doc,o)p.viewFrom?ho(r):(p.viewFrom+=u,p.viewTo+=u);else if(o<=p.viewFrom&&c>=p.viewTo)ho(r);else if(o<=p.viewFrom){var g=mo(r,c,c+u,1);g?(p.view=p.view.slice(g.index),p.viewFrom=g.lineN,p.viewTo+=u):ho(r)}else if(c>=p.viewTo){var y=mo(r,o,o,-1);y?(p.view=p.view.slice(0,y.index),p.viewTo=y.lineN):ho(r)}else{var C=mo(r,o,o,-1),_=mo(r,c,c+u,1);C&&_?(p.view=p.view.slice(0,C.index).concat(Qs(r,C.lineN,_.lineN)).concat(p.view.slice(_.index)),p.viewTo+=u):ho(r)}var E=p.externalMeasured;E&&(c=p.lineN&&o=u.viewTo)){var g=u.view[Ua(r,o)];if(g.node!=null){var y=g.changes||(g.changes=[]);Ue(y,c)==-1&&y.push(c)}}}i(ta,"regLineChange");function ho(r){r.display.viewFrom=r.display.viewTo=r.doc.first,r.display.view=[],r.display.viewOffset=0}i(ho,"resetView");function mo(r,o,c,u){var p=Ua(r,o),g,y=r.display.view;if(!Di||c==r.doc.first+r.doc.size)return{index:p,lineN:c};for(var C=r.display.viewFrom,_=0;_0){if(p==y.length-1)return null;g=C+y[p].size-o,p++}else g=C-o;o+=g,c+=g}for(;Fa(r.doc,c)!=c;){if(p==(u<0?0:y.length-1))return null;c+=u*y[p-(u<0?1:0)].size,p+=u}return{index:p,lineN:c}}i(mo,"viewCuttingPoint");function id(r,o,c){var u=r.display,p=u.view;p.length==0||o>=u.viewTo||c<=u.viewFrom?(u.view=Qs(r,o,c),u.viewFrom=o):(u.viewFrom>o?u.view=Qs(r,o,u.viewFrom).concat(u.view):u.viewFromc&&(u.view=u.view.slice(0,Ua(r,c)))),u.viewTo=c}i(id,"adjustView");function Qp(r){for(var o=r.display.view,c=0,u=0;u=r.display.viewTo||_.to().line0?y:r.defaultCharWidth())+"px"}if(u.other){var C=c.appendChild(xe("div","\xA0","CodeMirror-cursor CodeMirror-secondarycursor"));C.style.display="",C.style.left=u.other.left+"px",C.style.top=u.other.top+"px",C.style.height=(u.other.bottom-u.other.top)*.85+"px"}}i(od,"drawSelectionCursor");function Wa(r,o){return r.top-o.top||r.left-o.left}i(Wa,"cmpCoords");function mg(r,o,c){var u=r.display,p=r.doc,g=document.createDocumentFragment(),y=Tc(r.display),C=y.left,_=Math.max(u.sizerWidth,$o(r)-u.sizer.offsetLeft)-y.right,E=p.direction=="ltr";function O(ye,ke,Ie,Oe){ke<0&&(ke=0),ke=Math.round(ke),Oe=Math.round(Oe),g.appendChild(xe("div",null,"CodeMirror-selected","position: absolute; left: "+ye+`px; + top: `+ke+"px; width: "+(Ie??_-ye)+`px; + height: `+(Oe-ke)+"px"))}i(O,"add");function F(ye,ke,Ie){var Oe=Pe(p,ye),it=Oe.text.length,Dt,pr;function Qt(xr,Nn){return ie(r,ce(ye,xr),"div",Oe,Nn)}i(Qt,"coords");function ar(xr,Nn,en){var Pr=Ht(r,Oe,null,xr),Cr=Nn=="ltr"==(en=="after")?"left":"right",lr=en=="after"?Pr.begin:Pr.end-(/\s/.test(Oe.text.charAt(Pr.end-1))?2:1);return Qt(lr,Cr)[Cr]}i(ar,"wrapX");var Sr=Me(Oe,p.direction);return bl(Sr,ke||0,Ie??it,function(xr,Nn,en,Pr){var Cr=en=="ltr",lr=Qt(xr,Cr?"left":"right"),$n=Qt(Nn-1,Cr?"right":"left"),yu=ke==null&&xr==0,ha=Ie==null&&Nn==it,yn=Pr==0,Jo=!Sr||Pr==Sr.length-1;if($n.top-lr.top<=3){var zr=(E?yu:ha)&&yn,Nh=(E?ha:yu)&&Jo,Zo=zr?C:(Cr?lr:$n).left,ma=Nh?_:(Cr?$n:lr).right;O(Zo,lr.top,ma-Zo,lr.bottom)}else{var ga,An,wu,Ah;Cr?(ga=E&&yu&&yn?C:lr.left,An=E?_:ar(xr,en,"before"),wu=E?C:ar(Nn,en,"after"),Ah=E&&ha&&Jo?_:$n.right):(ga=E?ar(xr,en,"before"):C,An=!E&&yu&&yn?_:lr.right,wu=!E&&ha&&Jo?C:$n.left,Ah=E?ar(Nn,en,"after"):_),O(ga,lr.top,An-ga,lr.bottom),lr.bottom<$n.top&&O(C,lr.bottom,null,$n.top),O(wu,$n.top,Ah-wu,$n.bottom)}(!Dt||Wa(lr,Dt)<0)&&(Dt=lr),Wa($n,Dt)<0&&(Dt=$n),(!pr||Wa(lr,pr)<0)&&(pr=lr),Wa($n,pr)<0&&(pr=$n)}),{start:Dt,end:pr}}i(F,"drawForLine");var K=o.from(),V=o.to();if(K.line==V.line)F(K.line,K.ch,V.ch);else{var te=Pe(p,K.line),ae=Pe(p,V.line),de=Rt(te)==Rt(ae),we=F(K.line,K.ch,de?te.text.length+1:null).end,_e=F(V.line,de?0:null,V.ch).start;de&&(we.top<_e.top-2?(O(we.right,we.top,null,we.bottom),O(C,_e.top,_e.left,_e.bottom)):O(we.right,we.top,_e.left-we.right,we.bottom)),we.bottom<_e.top&&O(C,we.bottom,null,_e.top)}c.appendChild(g)}i(mg,"drawSelectionRange");function $a(r){if(r.state.focused){var o=r.display;clearInterval(o.blinker);var c=!0;o.cursorDiv.style.visibility="",r.options.cursorBlinkRate>0?o.blinker=setInterval(function(){r.hasFocus()||Jl(r),o.cursorDiv.style.visibility=(c=!c)?"":"hidden"},r.options.cursorBlinkRate):r.options.cursorBlinkRate<0&&(o.cursorDiv.style.visibility="hidden")}}i($a,"restartBlink");function na(r){r.hasFocus()||(r.display.input.focus(),r.state.focused||Zp(r))}i(na,"ensureFocus");function Ql(r){r.state.delayingBlurEvent=!0,setTimeout(function(){r.state.delayingBlurEvent&&(r.state.delayingBlurEvent=!1,r.state.focused&&Jl(r))},100)}i(Ql,"delayBlurEvent");function Zp(r,o){r.state.delayingBlurEvent&&!r.state.draggingText&&(r.state.delayingBlurEvent=!1),r.options.readOnly!="nocursor"&&(r.state.focused||(Mt(r,"focus",r,o),r.state.focused=!0,It(r.display.wrapper,"CodeMirror-focused"),!r.curOp&&r.display.selForContextMenu!=r.doc.sel&&(r.display.input.reset(),S&&setTimeout(function(){return r.display.input.reset(!0)},20)),r.display.input.receivedFocus()),$a(r))}i(Zp,"onFocus");function Jl(r,o){r.state.delayingBlurEvent||(r.state.focused&&(Mt(r,"blur",r,o),r.state.focused=!1,Ee(r.display.wrapper,"CodeMirror-focused")),clearInterval(r.display.blinker),setTimeout(function(){r.state.focused||(r.display.shift=!1)},150))}i(Jl,"onBlur");function sd(r){for(var o=r.display,c=o.lineDiv.offsetTop,u=Math.max(0,o.scroller.getBoundingClientRect().top),p=o.lineDiv.getBoundingClientRect().top,g=0,y=0;y.005||V<-.005)&&(pr.display.sizerWidth){var ae=Math.ceil(O/Cs(r.display));ae>r.display.maxLineLength&&(r.display.maxLineLength=ae,r.display.maxLine=C.line,r.display.maxLineChanged=!0)}}}Math.abs(g)>2&&(o.scroller.scrollTop+=g)}i(sd,"updateHeightsInViewport");function Ac(r){if(r.widgets)for(var o=0;o=y&&(g=ys(o,vi(Pe(o,_))-r.wrapper.clientHeight),y=_)}return{from:g,to:Math.max(y,g+1)}}i(Va,"visibleLines");function eh(r,o){if(!Pt(r,"scrollCursorIntoView")){var c=r.display,u=c.sizer.getBoundingClientRect(),p=null,g=c.wrapper.ownerDocument;if(o.top+u.top<0?p=!0:o.bottom+u.top>(g.defaultView.innerHeight||g.documentElement.clientHeight)&&(p=!1),p!=null&&!Q){var y=xe("div","\u200B",null,`position: absolute; + top: `+(o.top-c.viewOffset-ea(r.display))+`px; + height: `+(o.bottom-o.top+Fi(r)+c.barHeight)+`px; + left: `+o.left+"px; width: "+Math.max(2,o.right-o.left)+"px;");r.display.lineSpace.appendChild(y),y.scrollIntoView(p),r.display.lineSpace.removeChild(y)}}}i(eh,"maybeScrollWindow");function dw(r,o,c,u){u==null&&(u=0);var p;!r.options.lineWrapping&&o==c&&(c=o.sticky=="before"?ce(o.line,o.ch+1,"before"):o,o=o.ch?ce(o.line,o.sticky=="before"?o.ch-1:o.ch,"after"):o);for(var g=0;g<5;g++){var y=!1,C=J(r,o),_=!c||c==o?C:J(r,c);p={left:Math.min(C.left,_.left),top:Math.min(C.top,_.top)-u,right:Math.max(C.left,_.left),bottom:Math.max(C.bottom,_.bottom)+u};var E=th(r,p),O=r.doc.scrollTop,F=r.doc.scrollLeft;if(E.scrollTop!=null&&(Pc(r,E.scrollTop),Math.abs(r.doc.scrollTop-O)>1&&(y=!0)),E.scrollLeft!=null&&(go(r,E.scrollLeft),Math.abs(r.doc.scrollLeft-F)>1&&(y=!0)),!y)break}return p}i(dw,"scrollPosIntoView");function gg(r,o){var c=th(r,o);c.scrollTop!=null&&Pc(r,c.scrollTop),c.scrollLeft!=null&&go(r,c.scrollLeft)}i(gg,"scrollIntoView");function th(r,o){var c=r.display,u=po(r.display);o.top<0&&(o.top=0);var p=r.curOp&&r.curOp.scrollTop!=null?r.curOp.scrollTop:c.scroller.scrollTop,g=jl(r),y={};o.bottom-o.top>g&&(o.bottom=o.top+g);var C=r.doc.height+ql(c),_=o.topC-u;if(o.topp+g){var O=Math.min(o.top,(E?C:o.bottom)-g);O!=p&&(y.scrollTop=O)}var F=r.options.fixedGutter?0:c.gutters.offsetWidth,K=r.curOp&&r.curOp.scrollLeft!=null?r.curOp.scrollLeft:c.scroller.scrollLeft-F,V=$o(r)-c.gutters.offsetWidth,te=o.right-o.left>V;return te&&(o.right=o.left+V),o.left<10?y.scrollLeft=0:o.leftV+K-3&&(y.scrollLeft=o.right+(te?0:10)-V),y}i(th,"calculateScrollPos");function rh(r,o){o!=null&&(ad(r),r.curOp.scrollTop=(r.curOp.scrollTop==null?r.doc.scrollTop:r.curOp.scrollTop)+o)}i(rh,"addToScrollTop");function er(r){ad(r);var o=r.getCursor();r.curOp.scrollToPos={from:o,to:o,margin:r.options.cursorScrollMargin}}i(er,"ensureCursorVisible");function Ar(r,o,c){(o!=null||c!=null)&&ad(r),o!=null&&(r.curOp.scrollLeft=o),c!=null&&(r.curOp.scrollTop=c)}i(Ar,"scrollToCoords");function pw(r,o){ad(r),r.curOp.scrollToPos=o}i(pw,"scrollToRange");function ad(r){var o=r.curOp.scrollToPos;if(o){r.curOp.scrollToPos=null;var c=Ae(r,o.from),u=Ae(r,o.to);nh(r,c,u,o.margin)}}i(ad,"resolveScrollToPos");function nh(r,o,c,u){var p=th(r,{left:Math.min(o.left,c.left),top:Math.min(o.top,c.top)-u,right:Math.max(o.right,c.right),bottom:Math.max(o.bottom,c.bottom)+u});Ar(r,p.scrollLeft,p.scrollTop)}i(nh,"scrollToCoordsRange");function Pc(r,o){Math.abs(r.doc.scrollTop-o)<2||(n||vo(r,{top:o}),ld(r,o,!0),n&&vo(r),Oc(r,100))}i(Pc,"updateScrollTop");function ld(r,o,c){o=Math.max(0,Math.min(r.display.scroller.scrollHeight-r.display.scroller.clientHeight,o)),!(r.display.scroller.scrollTop==o&&!c)&&(r.doc.scrollTop=o,r.display.scrollbars.setScrollTop(o),r.display.scroller.scrollTop!=o&&(r.display.scroller.scrollTop=o))}i(ld,"setScrollTop");function go(r,o,c,u){o=Math.max(0,Math.min(o,r.display.scroller.scrollWidth-r.display.scroller.clientWidth)),!((c?o==r.doc.scrollLeft:Math.abs(r.doc.scrollLeft-o)<2)&&!u)&&(r.doc.scrollLeft=o,Sg(r),r.display.scroller.scrollLeft!=o&&(r.display.scroller.scrollLeft=o),r.display.scrollbars.setScrollLeft(o))}i(go,"setScrollLeft");function qa(r){var o=r.display,c=o.gutters.offsetWidth,u=Math.round(r.doc.height+ql(r.display));return{clientHeight:o.scroller.clientHeight,viewHeight:o.wrapper.clientHeight,scrollWidth:o.scroller.scrollWidth,clientWidth:o.scroller.clientWidth,viewWidth:o.wrapper.clientWidth,barLeft:r.options.fixedGutter?c:0,docHeight:u,scrollHeight:u+Fi(r)+o.barHeight,nativeBarWidth:o.nativeBarWidth,gutterWidth:c}}i(qa,"measureForScrollbars");var Hi=i(function(r,o,c){this.cm=c;var u=this.vert=xe("div",[xe("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),p=this.horiz=xe("div",[xe("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");u.tabIndex=p.tabIndex=-1,r(u),r(p),ze(u,"scroll",function(){u.clientHeight&&o(u.scrollTop,"vertical")}),ze(p,"scroll",function(){p.clientWidth&&o(p.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,d&&v<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")},"NativeScrollbars");Hi.prototype.update=function(r){var o=r.scrollWidth>r.clientWidth+1,c=r.scrollHeight>r.clientHeight+1,u=r.nativeBarWidth;if(c){this.vert.style.display="block",this.vert.style.bottom=o?u+"px":"0";var p=r.viewHeight-(o?u:0);this.vert.firstChild.style.height=Math.max(0,r.scrollHeight-r.clientHeight+p)+"px"}else this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0";if(o){this.horiz.style.display="block",this.horiz.style.right=c?u+"px":"0",this.horiz.style.left=r.barLeft+"px";var g=r.viewWidth-r.barLeft-(c?u:0);this.horiz.firstChild.style.width=Math.max(0,r.scrollWidth-r.clientWidth+g)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&r.clientHeight>0&&(u==0&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:c?u:0,bottom:o?u:0}},Hi.prototype.setScrollLeft=function(r){this.horiz.scrollLeft!=r&&(this.horiz.scrollLeft=r),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Hi.prototype.setScrollTop=function(r){this.vert.scrollTop!=r&&(this.vert.scrollTop=r),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Hi.prototype.zeroWidthHack=function(){var r=B&&!q?"12px":"18px";this.horiz.style.height=this.vert.style.width=r,this.horiz.style.visibility=this.vert.style.visibility="hidden",this.disableHoriz=new se,this.disableVert=new se},Hi.prototype.enableZeroWidthBar=function(r,o,c){r.style.visibility="";function u(){var p=r.getBoundingClientRect(),g=c=="vert"?document.elementFromPoint(p.right-1,(p.top+p.bottom)/2):document.elementFromPoint((p.right+p.left)/2,p.bottom-1);g!=r?r.style.visibility="hidden":o.set(1e3,u)}i(u,"maybeDisable"),o.set(1e3,u)},Hi.prototype.clear=function(){var r=this.horiz.parentNode;r.removeChild(this.horiz),r.removeChild(this.vert)};var _s=i(function(){},"NullScrollbars");_s.prototype.update=function(){return{bottom:0,right:0}},_s.prototype.setScrollLeft=function(){},_s.prototype.setScrollTop=function(){},_s.prototype.clear=function(){};function Ko(r,o){o||(o=qa(r));var c=r.display.barWidth,u=r.display.barHeight;Lc(r,o);for(var p=0;p<4&&c!=r.display.barWidth||u!=r.display.barHeight;p++)c!=r.display.barWidth&&r.options.lineWrapping&&sd(r),Lc(r,qa(r)),c=r.display.barWidth,u=r.display.barHeight}i(Ko,"updateScrollbars");function Lc(r,o){var c=r.display,u=c.scrollbars.update(o);c.sizer.style.paddingRight=(c.barWidth=u.right)+"px",c.sizer.style.paddingBottom=(c.barHeight=u.bottom)+"px",c.heightForcer.style.borderBottom=u.bottom+"px solid transparent",u.right&&u.bottom?(c.scrollbarFiller.style.display="block",c.scrollbarFiller.style.height=u.bottom+"px",c.scrollbarFiller.style.width=u.right+"px"):c.scrollbarFiller.style.display="",u.bottom&&r.options.coverGutterNextToScrollbar&&r.options.fixedGutter?(c.gutterFiller.style.display="block",c.gutterFiller.style.height=u.bottom+"px",c.gutterFiller.style.width=o.gutterWidth+"px"):c.gutterFiller.style.display=""}i(Lc,"updateScrollbarsInner");var ja={native:Hi,null:_s};function vg(r){r.display.scrollbars&&(r.display.scrollbars.clear(),r.display.scrollbars.addClass&&Ee(r.display.wrapper,r.display.scrollbars.addClass)),r.display.scrollbars=new ja[r.options.scrollbarStyle](function(o){r.display.wrapper.insertBefore(o,r.display.scrollbarFiller),ze(o,"mousedown",function(){r.state.focused&&setTimeout(function(){return r.display.input.focus()},0)}),o.setAttribute("cm-not-content","true")},function(o,c){c=="horizontal"?go(r,o):Pc(r,o)},r),r.display.scrollbars.addClass&&It(r.display.wrapper,r.display.scrollbars.addClass)}i(vg,"initScrollbars");var hw=0;function Ka(r){r.curOp={cm:r,viewChanged:!1,startHeight:r.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++hw,markArrays:null},Jf(r.curOp)}i(Ka,"startOperation");function Ga(r){var o=r.curOp;o&&xc(o,function(c){for(var u=0;u=c.viewTo)||c.maxLineChanged&&o.options.lineWrapping,r.update=r.mustUpdate&&new Go(o,r.mustUpdate&&{top:r.scrollTop,ensure:r.scrollToPos},r.forceUpdate)}i(ud,"endOperation_R1");function Mc(r){r.updatedDisplay=r.mustUpdate&&ih(r.cm,r.update)}i(Mc,"endOperation_W1");function yg(r){var o=r.cm,c=o.display;r.updatedDisplay&&sd(o),r.barMeasure=qa(o),c.maxLineChanged&&!o.options.lineWrapping&&(r.adjustWidthTo=Kl(o,c.maxLine,c.maxLine.text.length).left+3,o.display.sizerWidth=r.adjustWidthTo,r.barMeasure.scrollWidth=Math.max(c.scroller.clientWidth,c.sizer.offsetLeft+r.adjustWidthTo+Fi(o)+o.display.barWidth),r.maxScrollLeft=Math.max(0,c.sizer.offsetLeft+r.adjustWidthTo-$o(o))),(r.updatedDisplay||r.selectionChanged)&&(r.preparedSelection=c.input.prepareSelection())}i(yg,"endOperation_R2");function A(r){var o=r.cm;r.adjustWidthTo!=null&&(o.display.sizer.style.minWidth=r.adjustWidthTo+"px",r.maxScrollLeft=r.display.viewTo)){var c=+new Date+r.options.workTime,u=Ss(r,o.highlightFrontier),p=[];o.iter(u.line,Math.min(o.first+o.size,r.display.viewTo+500),function(g){if(u.line>=r.display.viewFrom){var y=g.styles,C=g.text.length>r.options.maxHighlightLength?Oi(o.mode,u.state):null,_=Ll(r,g,u,!0);C&&(u.state=C),g.styles=_.styles;var E=g.styleClasses,O=_.classes;O?g.styleClasses=O:E&&(g.styleClasses=null);for(var F=!y||y.length!=g.styles.length||E!=O&&(!E||!O||E.bgClass!=O.bgClass||E.textClass!=O.textClass),K=0;!F&&Kc)return Oc(r,r.options.workDelay),!0}),o.highlightFrontier=u.line,o.modeFrontier=Math.max(o.modeFrontier,u.line),p.length&&vn(r,function(){for(var g=0;g=c.viewFrom&&o.visible.to<=c.viewTo&&(c.updateLineNumbers==null||c.updateLineNumbers>=c.viewTo)&&c.renderedView==c.view&&Qp(r)==0)return!1;xg(r)&&(ho(r),o.dims=Xl(r));var p=u.first+u.size,g=Math.max(o.visible.from-r.options.viewportMargin,u.first),y=Math.min(p,o.visible.to+r.options.viewportMargin);c.viewFromy&&c.viewTo-y<20&&(y=Math.min(p,c.viewTo)),Di&&(g=Fa(r.doc,g),y=Uo(r.doc,y));var C=g!=c.viewFrom||y!=c.viewTo||c.lastWrapHeight!=o.wrapperHeight||c.lastWrapWidth!=o.wrapperWidth;id(r,g,y),c.viewOffset=vi(Pe(r.doc,c.viewFrom)),r.display.mover.style.top=c.viewOffset+"px";var _=Qp(r);if(!C&&_==0&&!o.force&&c.renderedView==c.view&&(c.updateLineNumbers==null||c.updateLineNumbers>=c.viewTo))return!1;var E=yw(r);return _>4&&(c.lineDiv.style.display="none"),Sw(r,c.updateLineNumbers,o.dims),_>4&&(c.lineDiv.style.display=""),c.renderedView=c.view,ww(E),Ye(c.cursorDiv),Ye(c.selectionDiv),c.gutters.style.height=c.sizer.style.minHeight=0,C&&(c.lastWrapHeight=o.wrapperHeight,c.lastWrapWidth=o.wrapperWidth,Oc(r,400)),c.updateLineNumbers=null,!0}i(ih,"updateDisplayIfNeeded");function wg(r,o){for(var c=o.viewport,u=!0;;u=!1){if(!u||!r.options.lineWrapping||o.oldDisplayWidth==$o(r)){if(c&&c.top!=null&&(c={top:Math.min(r.doc.height+ql(r.display)-jl(r),c.top)}),o.visible=Va(r.display,r.doc,c),o.visible.from>=r.display.viewFrom&&o.visible.to<=r.display.viewTo)break}else u&&(o.visible=Va(r.display,r.doc,c));if(!ih(r,o))break;sd(r);var p=qa(r);ra(r),Ko(r,p),sh(r,p),o.force=!1}o.signal(r,"update",r),(r.display.viewFrom!=r.display.reportedViewFrom||r.display.viewTo!=r.display.reportedViewTo)&&(o.signal(r,"viewportChange",r,r.display.viewFrom,r.display.viewTo),r.display.reportedViewFrom=r.display.viewFrom,r.display.reportedViewTo=r.display.viewTo)}i(wg,"postUpdateDisplay");function vo(r,o){var c=new Go(r,o);if(ih(r,c)){sd(r),wg(r,c);var u=qa(r);ra(r),Ko(r,u),sh(r,u),c.finish()}}i(vo,"updateDisplaySimple");function Sw(r,o,c){var u=r.display,p=r.options.lineNumbers,g=u.lineDiv,y=g.firstChild;function C(te){var ae=te.nextSibling;return S&&B&&r.display.currentWheelTarget==te?te.style.display="none":te.parentNode.removeChild(te),ae}i(C,"rm");for(var _=u.view,E=u.viewFrom,O=0;O<_.length;O++){var F=_[O];if(!F.hidden)if(!F.node||F.node.parentNode!=g){var K=Yp(r,F,E,c);g.insertBefore(K,y)}else{for(;y!=F.node;)y=C(y);var V=p&&o!=null&&o<=E&&F.lineNumber;F.changes&&(Ue(F.changes,"gutter")>-1&&(V=!1),Cc(r,F,E,c)),V&&(Ye(F.lineNumber),F.lineNumber.appendChild(document.createTextNode(Oa(r.options,E)))),y=F.node.nextSibling}E+=F.size}for(;y;)y=C(y)}i(Sw,"patchDisplay");function oh(r){var o=r.gutters.offsetWidth;r.sizer.style.marginLeft=o+"px",Kt(r,"gutterChanged",r)}i(oh,"updateGutterSpace");function sh(r,o){r.display.sizer.style.minHeight=o.docHeight+"px",r.display.heightForcer.style.top=o.docHeight+"px",r.display.gutters.style.height=o.docHeight+r.display.barHeight+Fi(r)+"px"}i(sh,"setDocumentHeight");function Sg(r){var o=r.display,c=o.view;if(!(!o.alignWidgets&&(!o.gutters.firstChild||!r.options.fixedGutter))){for(var u=kt(o)-o.scroller.scrollLeft+r.doc.scrollLeft,p=o.gutters.offsetWidth,g=u+"px",y=0;y=105&&(p.wrapper.style.clipPath="inset(0px)"),p.wrapper.setAttribute("translate","no"),d&&v<8&&(p.gutters.style.zIndex=-1,p.scroller.style.paddingRight=0),!S&&!(n&&L)&&(p.scroller.draggable=!0),r&&(r.appendChild?r.appendChild(p.wrapper):r(p.wrapper)),p.viewFrom=p.viewTo=o.first,p.reportedViewFrom=p.reportedViewTo=o.first,p.view=[],p.renderedView=null,p.externalMeasured=null,p.viewOffset=0,p.lastWrapHeight=p.lastWrapWidth=0,p.updateLineNumbers=null,p.nativeBarWidth=p.barHeight=p.barWidth=0,p.scrollbarsClipped=!1,p.lineNumWidth=p.lineNumInnerWidth=p.lineNumChars=null,p.alignWidgets=!1,p.cachedCharWidth=p.cachedTextHeight=p.cachedPaddingH=null,p.maxLine=null,p.maxLineLength=0,p.maxLineChanged=!1,p.wheelDX=p.wheelDY=p.wheelStartX=p.wheelStartY=null,p.shift=!1,p.selForContextMenu=null,p.activeTouch=null,p.gutterSpecs=yo(u.gutters,u.lineNumbers),Cg(p),c.init(p)}i(xw,"Display");var cd=0,Es=null;d?Es=-.53:n?Es=15:k?Es=-.7:z&&(Es=-1/3);function ia(r){var o=r.wheelDeltaX,c=r.wheelDeltaY;return o==null&&r.detail&&r.axis==r.HORIZONTAL_AXIS&&(o=r.detail),c==null&&r.detail&&r.axis==r.VERTICAL_AXIS?c=r.detail:c==null&&(c=r.wheelDelta),{x:o,y:c}}i(ia,"wheelEventDelta");function Cw(r){var o=ia(r);return o.x*=Es,o.y*=Es,o}i(Cw,"wheelEventPixels");function _g(r,o){k&&R==102&&(r.display.chromeScrollHack==null?r.display.sizer.style.pointerEvents="none":clearTimeout(r.display.chromeScrollHack),r.display.chromeScrollHack=setTimeout(function(){r.display.chromeScrollHack=null,r.display.sizer.style.pointerEvents=""},100));var c=ia(o),u=c.x,p=c.y,g=Es;o.deltaMode===0&&(u=o.deltaX,p=o.deltaY,g=1);var y=r.display,C=y.scroller,_=C.scrollWidth>C.clientWidth,E=C.scrollHeight>C.clientHeight;if(u&&_||p&&E){if(p&&B&&S){e:for(var O=o.target,F=y.view;O!=C;O=O.parentNode)for(var K=0;K=0&&Ve(r,u.to())<=0)return c}return-1};var Et=i(function(r,o){this.anchor=r,this.head=o},"Range");Et.prototype.from=function(){return zo(this.anchor,this.head)},Et.prototype.to=function(){return js(this.anchor,this.head)},Et.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch};function wo(r,o,c){var u=r&&r.options.selectionsMayTouch,p=o[c];o.sort(function(K,V){return Ve(K.from(),V.from())}),c=Ue(o,p);for(var g=1;g0:_>=0){var E=zo(C.from(),y.from()),O=js(C.to(),y.to()),F=C.empty()?y.from()==y.head:C.from()==C.head;g<=c&&--c,o.splice(--g,2,new Et(F?O:E,F?E:O))}}return new sr(o,c)}i(wo,"normalizeSelection");function oa(r,o){return new sr([new Et(r,o||r)],0)}i(oa,"simpleSelection");function sa(r){return r.text?ce(r.from.line+r.text.length-1,lt(r.text).length+(r.text.length==1?r.from.ch:0)):r.to}i(sa,"changeEnd");function Eg(r,o){if(Ve(r,o.from)<0)return r;if(Ve(r,o.to)<=0)return sa(o);var c=r.line+o.text.length-(o.to.line-o.from.line)-1,u=r.ch;return r.line==o.to.line&&(u+=sa(o).ch-o.to.ch),ce(c,u)}i(Eg,"adjustForChange");function fd(r,o){for(var c=[],u=0;u1&&r.remove(C.line+1,te-1),r.insert(C.line+1,we)}Kt(r,"change",r,o)}i(tu,"updateDoc");function aa(r,o,c){function u(p,g,y){if(p.linked)for(var C=0;C1&&!r.done[r.done.length-2].ranges)return r.done.pop(),lt(r.done)}i(Ew,"lastChangeEvent");function ch(r,o,c,u){var p=r.history;p.undone.length=0;var g=+new Date,y,C;if((p.lastOp==u||p.lastOrigin==o.origin&&o.origin&&(o.origin.charAt(0)=="+"&&p.lastModTime>g-(r.cm?r.cm.options.historyEventDelay:500)||o.origin.charAt(0)=="*"))&&(y=Ew(p,p.lastOp==u)))C=lt(y.changes),Ve(o.from,o.to)==0&&Ve(o.from,C.to)==0?C.to=sa(o):y.changes.push(Ts(r,o));else{var _=lt(p.done);for((!_||!_.ranges)&&So(r.sel,p.done),y={changes:[Ts(r,o)],generation:p.generation},p.done.push(y);p.done.length>p.undoDepth;)p.done.shift(),p.done[0].ranges||p.done.shift()}p.done.push(c),p.generation=++p.maxGeneration,p.lastModTime=p.lastSelTime=g,p.lastOp=p.lastSelOp=u,p.lastOrigin=p.lastSelOrigin=o.origin,C||Mt(r,"historyAdded")}i(ch,"addChangeToHistory");function Tg(r,o,c,u){var p=o.charAt(0);return p=="*"||p=="+"&&c.ranges.length==u.ranges.length&&c.somethingSelected()==u.somethingSelected()&&new Date-r.history.lastSelTime<=(r.cm?r.cm.options.historyEventDelay:500)}i(Tg,"selectionEventCanBeMerged");function Dc(r,o,c,u){var p=r.history,g=u&&u.origin;c==p.lastSelOp||g&&p.lastSelOrigin==g&&(p.lastModTime==p.lastSelTime&&p.lastOrigin==g||Tg(r,g,lt(p.done),o))?p.done[p.done.length-1]=o:So(o,p.done),p.lastSelTime=+new Date,p.lastSelOrigin=g,p.lastSelOp=c,u&&u.clearRedo!==!1&&wi(p.undone)}i(Dc,"addSelectionToHistory");function So(r,o){var c=lt(o);c&&c.ranges&&c.equals(r)||o.push(r)}i(So,"pushSelectionToHistory");function fh(r,o,c,u){var p=o["spans_"+r.id],g=0;r.iter(Math.max(r.first,c),Math.min(r.first+r.size,u),function(y){y.markedSpans&&((p||(p=o["spans_"+r.id]={}))[g]=y.markedSpans),++g})}i(fh,"attachLocalSpans");function bw(r){if(!r)return null;for(var o,c=0;c-1&&(lt(C)[F]=E[F],delete E[F])}}return u}i(Xa,"copyHistoryArray");function Fr(r,o,c,u){if(u){var p=r.anchor;if(c){var g=Ve(o,p)<0;g!=Ve(c,p)<0?(p=o,o=c):g!=Ve(o,c)<0&&(o=c)}return new Et(p,o)}else return new Et(c||o,o)}i(Fr,"extendRange");function nu(r,o,c,u,p){p==null&&(p=r.cm&&(r.cm.display.shift||r.extend)),Jr(r,new sr([Fr(r.sel.primary(),o,c,p)],0),u)}i(nu,"extendSelection");function dh(r,o,c){for(var u=[],p=r.cm&&(r.cm.display.shift||r.extend),g=0;g=o.ch:C.to>o.ch))){if(p&&(Mt(_,"beforeCursorEnter"),_.explicitlyCleared))if(g.markedSpans){--y;continue}else break;if(!_.atomic)continue;if(c){var F=_.find(u<0?1:-1),K=void 0;if((u<0?O:E)&&(F=Pg(r,F,-u,F&&F.line==o.line?g:null)),F&&F.line==o.line&&(K=Ve(F,c))&&(u<0?K<0:K>0))return iu(r,F,o,u,p)}var V=_.find(u<0?-1:1);return(u<0?E:O)&&(V=Pg(r,V,u,V.line==o.line?g:null)),V?iu(r,V,o,u,p):null}}return o}i(iu,"skipAtomicInner");function ou(r,o,c,u,p){var g=u||1,y=iu(r,o,c,g,p)||!p&&iu(r,o,c,g,!0)||iu(r,o,c,-g,p)||!p&&iu(r,o,c,-g,!0);return y||(r.cantEdit=!0,ce(r.first,0))}i(ou,"skipAtomic");function Pg(r,o,c,u){return c<0&&o.ch==0?o.line>r.first?qe(r,ce(o.line-1)):null:c>0&&o.ch==(u||Pe(r,o.line)).text.length?o.line=0;--p)Lg(r,{from:u[p].from,to:u[p].to,text:p?[""]:o.text,origin:o.origin});else Lg(r,o)}}i(au,"makeChange");function Lg(r,o){if(!(o.text.length==1&&o.text[0]==""&&Ve(o.from,o.to)==0)){var c=fd(r,o);ch(r,o,c,r.cm?r.cm.curOp.id:NaN),Ic(r,o,c,yc(r,o));var u=[];aa(r,function(p,g){!g&&Ue(u,p.history)==-1&&(Dg(p.history,o),u.push(p.history)),Ic(p,o,null,yc(p,o))})}}i(Lg,"makeChangeInner");function ua(r,o,c){var u=r.cm&&r.cm.state.suppressEdits;if(!(u&&!c)){for(var p=r.history,g,y=r.sel,C=o=="undo"?p.done:p.undone,_=o=="undo"?p.undone:p.done,E=0;E=0;--V){var te=K(V);if(te)return te.v}}}}i(ua,"makeChangeFromHistory");function Mg(r,o){if(o!=0&&(r.first+=o,r.sel=new sr(wr(r.sel.ranges,function(p){return new Et(ce(p.anchor.line+o,p.anchor.ch),ce(p.head.line+o,p.head.ch))}),r.sel.primIndex),r.cm)){Wn(r.cm,r.first,r.first-o,o);for(var c=r.cm.display,u=c.viewFrom;ur.lastLine())){if(o.from.lineg&&(o={from:o.from,to:ce(g,Pe(r,g).text.length),text:[o.text[0]],origin:o.origin}),o.removed=lo(r,o.from,o.to),c||(c=fd(r,o)),r.cm?hh(r.cm,o,u):tu(r,o,u),Zr(r,c,st),r.cantEdit&&ou(r,ce(r.firstLine(),0))&&(r.cantEdit=!1)}}i(Ic,"makeChangeSingleDoc");function hh(r,o,c){var u=r.doc,p=r.display,g=o.from,y=o.to,C=!1,_=g.line;r.options.lineWrapping||(_=vt(Rt(Pe(u,g.line))),u.iter(_,y.line+1,function(V){if(V==p.maxLine)return C=!0,!0})),u.sel.contains(o.from,o.to)>-1&&Na(r),tu(u,o,c,hg(r)),r.options.lineWrapping||(u.iter(_,g.line+o.text.length,function(V){var te=Ze(V);te>p.maxLineLength&&(p.maxLine=V,p.maxLineLength=te,p.maxLineChanged=!0,C=!1)}),C&&(r.curOp.updateMaxLine=!0)),Ra(u,g.line),Oc(r,400);var E=o.text.length-(y.line-g.line)-1;o.full?Wn(r):g.line==y.line&&o.text.length==1&&!eu(r.doc,o)?ta(r,g.line,"text"):Wn(r,g.line,y.line+1,E);var O=dn(r,"changes"),F=dn(r,"change");if(F||O){var K={from:g,to:y,text:o.text,removed:o.removed,origin:o.origin};F&&Kt(r,"change",r,K),O&&(r.curOp.changeObjs||(r.curOp.changeObjs=[])).push(K)}r.display.selForContextMenu=null}i(hh,"makeChangeSingleDocInEditor");function Qa(r,o,c,u,p){var g;u||(u=c),Ve(u,c)<0&&(g=[u,c],c=g[0],u=g[1]),typeof o=="string"&&(o=r.splitLines(o)),au(r,{from:c,to:u,text:o,origin:p})}i(Qa,"replaceRange");function Og(r,o,c,u){c1||!(this.children[0]instanceof Ja))){var C=[];this.collapse(C),this.children=[new Ja(C)],this.children[0].parent=this}},"removeInner"),collapse:i(function(r){for(var o=0;o50){for(var y=p.lines.length%25+25,C=y;C10);r.parent.maybeSpill()}},"maybeSpill"),iterN:i(function(r,o,c){for(var u=0;ur.display.maxLineLength&&(r.display.maxLine=E,r.display.maxLineLength=O,r.display.maxLineChanged=!0)}u!=null&&r&&this.collapsed&&Wn(r,u,p+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,r&&Ng(r.doc)),r&&Kt(r,"markerCleared",r,this,u,p),o&&Ga(r),this.parent&&this.parent.clear()}},xo.prototype.find=function(r,o){r==null&&this.type=="bookmark"&&(r=1);for(var c,u,p=0;p0||y==0&&g.clearWhenEmpty!==!1)return g;if(g.replacedWith&&(g.collapsed=!0,g.widgetNode=Xe("span",[g.replacedWith],"CodeMirror-widget"),u.handleMouseEvents||g.widgetNode.setAttribute("cm-ignore-events","true"),u.insertLeft&&(g.widgetNode.insertLeft=!0)),g.collapsed){if(Kp(r,o.line,o,c,g)||o.line!=c.line&&Kp(r,c.line,o,c,g))throw new Error("Inserting collapsed marker partially overlapping an existing one");Wp()}g.addToHistory&&ch(r,{from:o,to:c,origin:"markText"},r.sel,NaN);var C=o.line,_=r.cm,E;if(r.iter(C,c.line+1,function(F){_&&g.collapsed&&!_.options.lineWrapping&&Rt(F)==_.display.maxLine&&(E=!0),g.collapsed&&C!=o.line&&Ri(F,0),vc(F,new Il(g,C==o.line?o.ch:null,C==c.line?c.ch:null),r.cm&&r.cm.curOp),++C}),g.collapsed&&r.iter(o.line,c.line+1,function(F){Se(r,F)&&Ri(F,0)}),g.clearOnEnter&&ze(g,"beforeCursorEnter",function(){return g.clear()}),g.readOnly&&(Kf(),(r.history.done.length||r.history.undone.length)&&r.clearHistory()),g.collapsed&&(g.id=++gh,g.atomic=!0),_){if(E&&(_.curOp.updateMaxLine=!0),g.collapsed)Wn(_,o.line,c.line+1);else if(g.className||g.startStyle||g.endStyle||g.css||g.attributes||g.title)for(var O=o.line;O<=c.line;O++)ta(_,O,"text");g.atomic&&Ng(_.doc),Kt(_,"markerAdded",_,g)}return g}i(uu,"markText");var cu=i(function(r,o){this.markers=r,this.primary=o;for(var c=0;c=0;_--)au(this,u[_]);C?la(this,C):this.cm&&er(this.cm)}),undo:Ir(function(){ua(this,"undo")}),redo:Ir(function(){ua(this,"redo")}),undoSelection:Ir(function(){ua(this,"undo",!0)}),redoSelection:Ir(function(){ua(this,"redo",!0)}),setExtending:i(function(r){this.extend=r},"setExtending"),getExtending:i(function(){return this.extend},"getExtending"),historySize:i(function(){for(var r=this.history,o=0,c=0,u=0;u=r.ch)&&o.push(p.marker.parent||p.marker)}return o},"findMarksAt"),findMarks:i(function(r,o,c){r=qe(this,r),o=qe(this,o);var u=[],p=r.line;return this.iter(r.line,o.line+1,function(g){var y=g.markedSpans;if(y)for(var C=0;C=_.to||_.from==null&&p!=r.line||_.from!=null&&p==o.line&&_.from>=o.ch)&&(!c||c(_.marker))&&u.push(_.marker.parent||_.marker)}++p}),u},"findMarks"),getAllMarks:i(function(){var r=[];return this.iter(function(o){var c=o.markedSpans;if(c)for(var u=0;ur)return o=r,!0;r-=g,++c}),qe(this,ce(c,o))},"posFromIndex"),indexFromPos:i(function(r){r=qe(this,r);var o=r.ch;if(r.lineo&&(o=r.from),r.to!=null&&r.to-1){o.state.draggingText(r),setTimeout(function(){return o.display.input.focus()},20);return}try{var O=r.dataTransfer.getData("Text");if(O){var F;if(o.state.draggingText&&!o.state.draggingText.copy&&(F=o.listSelections()),Zr(o.doc,oa(c,c)),F)for(var K=0;K=0;C--)Qa(r.doc,"",u[C].from,u[C].to,"+delete");er(r)})}i(ca,"deleteNearSelection");function yd(r,o,c){var u=Hn(r.text,o+c,c);return u<0||u>r.text.length?null:u}i(yd,"moveCharLogically");function Uc(r,o,c){var u=yd(r,o.ch,c);return u==null?null:new ce(o.line,u,c<0?"after":"before")}i(Uc,"moveLogically");function Wc(r,o,c,u,p){if(r){o.doc.direction=="rtl"&&(p=-p);var g=Me(c,o.doc.direction);if(g){var y=p<0?lt(g):g[0],C=p<0==(y.level==1),_=C?"after":"before",E;if(y.level>0||o.doc.direction=="rtl"){var O=Tn(o,c);E=p<0?c.text.length-1:0;var F=w(o,O,E).top;E=so(function(K){return w(o,O,K).top==F},p<0==(y.level==1)?y.from:y.to-1,E),_=="before"&&(E=yd(c,E,1))}else E=p<0?y.to:y.from;return new ce(u,E,_)}}return new ce(u,p<0?c.text.length:0,p<0?"before":"after")}i(Wc,"endOfLine");function fa(r,o,c,u){var p=Me(o,r.doc.direction);if(!p)return Uc(o,c,u);c.ch>=o.text.length?(c.ch=o.text.length,c.sticky="before"):c.ch<=0&&(c.ch=0,c.sticky="after");var g=ee(p,c.ch,c.sticky),y=p[g];if(r.doc.direction=="ltr"&&y.level%2==0&&(u>0?y.to>c.ch:y.from=y.from&&K>=O.begin)){var V=F?"before":"after";return new ce(c.line,K,V)}}var te=i(function(we,_e,ye){for(var ke=i(function(Dt,pr){return pr?new ce(c.line,C(Dt,1),"before"):new ce(c.line,Dt,"after")},"getRes");we>=0&&we0==(Ie.level!=1),it=Oe?ye.begin:C(ye.end,-1);if(Ie.from<=it&&it0?O.end:C(O.begin,-1);return de!=null&&!(u>0&&de==o.text.length)&&(ae=te(u>0?0:p.length-1,u,E(de)),ae)?ae:null}i(fa,"moveVisually");var $c={selectAll:su,singleSelection:i(function(r){return r.setSelection(r.getCursor("anchor"),r.getCursor("head"),st)},"singleSelection"),killLine:i(function(r){return ca(r,function(o){if(o.empty()){var c=Pe(r.doc,o.head.line).text.length;return o.head.ch==c&&o.head.line0)p=new ce(p.line,p.ch+1),r.replaceRange(g.charAt(p.ch-1)+g.charAt(p.ch-2),ce(p.line,p.ch-2),p,"+transpose");else if(p.line>r.doc.first){var y=Pe(r.doc,p.line-1).text;y&&(p=new ce(p.line,1),r.replaceRange(g.charAt(0)+r.doc.lineSeparator()+y.charAt(y.length-1),ce(p.line-1,y.length-1),p,"+transpose"))}}c.push(new Et(p,p))}r.setSelections(c)})},"transposeChars"),newlineAndIndent:i(function(r){return vn(r,function(){for(var o=r.listSelections(),c=o.length-1;c>=0;c--)r.replaceRange(r.doc.lineSeparator(),o[c].anchor,o[c].head,"+input");o=r.listSelections();for(var u=0;ur&&Ve(o,this.pos)==0&&c==this.button};var Xo,hu;function jg(r,o){var c=+new Date;return hu&&hu.compare(c,r,o)?(Xo=hu=null,"triple"):Xo&&Xo.compare(c,r,o)?(hu=new pu(c,r,o),Xo=null,"double"):(Xo=new pu(c,r,o),hu=null,"single")}i(jg,"clickRepeat");function Kg(r){var o=this,c=o.display;if(!(Pt(o,r)||c.activeTouch&&c.input.supportsTouch())){if(c.input.ensurePolled(),c.shift=r.shiftKey,yi(c,r)){S||(c.scroller.draggable=!1,setTimeout(function(){return c.scroller.draggable=!0},100));return}if(!gu(o,r)){var u=jo(o,r),p=nc(r),g=u?jg(u,p):"single";vr(o).focus(),p==1&&o.state.selectingText&&o.state.selectingText(r),!(u&&Gg(o,p,u,g,r))&&(p==1?u?qc(o,u,g,r):Pa(r)==c.scroller&&kr(r):p==2?(u&&nu(o.doc,u),setTimeout(function(){return c.input.focus()},20)):p==3&&(he?o.display.input.onContextMenu(r):Ql(o)))}}}i(Kg,"onMouseDown");function Gg(r,o,c,u,p){var g="Click";return u=="double"?g="Double"+g:u=="triple"&&(g="Triple"+g),g=(o==1?"Left":o==2?"Middle":"Right")+g,Vc(r,wh(g,p),p,function(y){if(typeof y=="string"&&(y=$c[y]),!y)return!1;var C=!1;try{r.isReadOnly()&&(r.state.suppressEdits=!0),C=y(r,c)!=Zt}finally{r.state.suppressEdits=!1}return C})}i(Gg,"handleMappedButton");function mu(r,o,c){var u=r.getOption("configureMouse"),p=u?u(r,o,c):{};if(p.unit==null){var g=j?c.shiftKey&&c.metaKey:c.altKey;p.unit=g?"rectangle":o=="single"?"char":o=="double"?"word":"line"}return(p.extend==null||r.doc.extend)&&(p.extend=r.doc.extend||c.shiftKey),p.addNew==null&&(p.addNew=B?c.metaKey:c.ctrlKey),p.moveOnDrag==null&&(p.moveOnDrag=!(B?c.altKey:c.ctrlKey)),p}i(mu,"configureMouse");function qc(r,o,c,u){d?setTimeout(yr(na,r),0):r.curOp.focus=ot(gr(r));var p=mu(r,c,u),g=r.doc.sel,y;r.options.dragDrop&&ic&&!r.isReadOnly()&&c=="single"&&(y=g.contains(o))>-1&&(Ve((y=g.ranges[y]).from(),o)<0||o.xRel>0)&&(Ve(y.to(),o)>0||o.xRel<0)?Rw(r,u,o,p):Yg(r,u,o,p)}i(qc,"leftButtonDown");function Rw(r,o,c,u){var p=r.display,g=!1,y=Lt(r,function(E){S&&(p.scroller.draggable=!1),r.state.draggingText=!1,r.state.delayingBlurEvent&&(r.hasFocus()?r.state.delayingBlurEvent=!1:Ql(r)),Yt(p.wrapper.ownerDocument,"mouseup",y),Yt(p.wrapper.ownerDocument,"mousemove",C),Yt(p.scroller,"dragstart",_),Yt(p.scroller,"drop",y),g||(kr(E),u.addNew||nu(r.doc,c,null,null,u.extend),S&&!z||d&&v==9?setTimeout(function(){p.wrapper.ownerDocument.body.focus({preventScroll:!0}),p.input.focus()},20):p.input.focus())}),C=i(function(E){g=g||Math.abs(o.clientX-E.clientX)+Math.abs(o.clientY-E.clientY)>=10},"mouseMove"),_=i(function(){return g=!0},"dragStart");S&&(p.scroller.draggable=!0),r.state.draggingText=y,y.copy=!u.moveOnDrag,ze(p.wrapper.ownerDocument,"mouseup",y),ze(p.wrapper.ownerDocument,"mousemove",C),ze(p.scroller,"dragstart",_),ze(p.scroller,"drop",y),r.state.delayingBlurEvent=!0,setTimeout(function(){return p.input.focus()},20),p.scroller.dragDrop&&p.scroller.dragDrop()}i(Rw,"leftButtonStartDrag");function Eh(r,o,c){if(c=="char")return new Et(o,o);if(c=="word")return r.findWordAt(o);if(c=="line")return new Et(ce(o.line,0),qe(r.doc,ce(o.line+1,0)));var u=c(r,o);return new Et(u.from,u.to)}i(Eh,"rangeForUnit");function Yg(r,o,c,u){d&&Ql(r);var p=r.display,g=r.doc;kr(o);var y,C,_=g.sel,E=_.ranges;if(u.addNew&&!u.extend?(C=g.sel.contains(c),C>-1?y=E[C]:y=new Et(c,c)):(y=g.sel.primary(),C=g.sel.primIndex),u.unit=="rectangle")u.addNew||(y=new Et(c,c)),c=jo(r,o,!0,!0),C=-1;else{var O=Eh(r,c,u.unit);u.extend?y=Fr(y,O.anchor,O.head,u.extend):y=O}u.addNew?C==-1?(C=E.length,Jr(g,wo(r,E.concat([y]),C),{scroll:!1,origin:"*mouse"})):E.length>1&&E[C].empty()&&u.unit=="char"&&!u.extend?(Jr(g,wo(r,E.slice(0,C).concat(E.slice(C+1)),0),{scroll:!1,origin:"*mouse"}),_=g.sel):zi(g,C,y,Fe):(C=0,Jr(g,new sr([y],0),Fe),_=g.sel);var F=c;function K(ye){if(Ve(F,ye)!=0)if(F=ye,u.unit=="rectangle"){for(var ke=[],Ie=r.options.tabSize,Oe=Ft(Pe(g,c.line).text,c.ch,Ie),it=Ft(Pe(g,ye.line).text,ye.ch,Ie),Dt=Math.min(Oe,it),pr=Math.max(Oe,it),Qt=Math.min(c.line,ye.line),ar=Math.min(r.lastLine(),Math.max(c.line,ye.line));Qt<=ar;Qt++){var Sr=Pe(g,Qt).text,xr=En(Sr,Dt,Ie);Dt==pr?ke.push(new Et(ce(Qt,xr),ce(Qt,xr))):Sr.length>xr&&ke.push(new Et(ce(Qt,xr),ce(Qt,En(Sr,pr,Ie))))}ke.length||ke.push(new Et(c,c)),Jr(g,wo(r,_.ranges.slice(0,C).concat(ke),C),{origin:"*mouse",scroll:!1}),r.scrollIntoView(ye)}else{var Nn=y,en=Eh(r,ye,u.unit),Pr=Nn.anchor,Cr;Ve(en.anchor,Pr)>0?(Cr=en.head,Pr=zo(Nn.from(),en.anchor)):(Cr=en.anchor,Pr=js(Nn.to(),en.head));var lr=_.ranges.slice(0);lr[C]=Sd(r,new Et(qe(g,Pr),Cr)),Jr(g,wo(r,lr,C),Fe)}}i(K,"extendTo");var V=p.wrapper.getBoundingClientRect(),te=0;function ae(ye){var ke=++te,Ie=jo(r,ye,!0,u.unit=="rectangle");if(Ie)if(Ve(Ie,F)!=0){r.curOp.focus=ot(gr(r)),K(Ie);var Oe=Va(p,g);(Ie.line>=Oe.to||Ie.lineV.bottom?20:0;it&&setTimeout(Lt(r,function(){te==ke&&(p.scroller.scrollTop+=it,ae(ye))}),50)}}i(ae,"extend");function de(ye){r.state.selectingText=!1,te=1/0,ye&&(kr(ye),p.input.focus()),Yt(p.wrapper.ownerDocument,"mousemove",we),Yt(p.wrapper.ownerDocument,"mouseup",_e),g.history.lastSelOrigin=null}i(de,"done");var we=Lt(r,function(ye){ye.buttons===0||!nc(ye)?de(ye):ae(ye)}),_e=Lt(r,de);r.state.selectingText=_e,ze(p.wrapper.ownerDocument,"mousemove",we),ze(p.wrapper.ownerDocument,"mouseup",_e)}i(Yg,"leftButtonSelect");function Sd(r,o){var c=o.anchor,u=o.head,p=Pe(r.doc,c.line);if(Ve(c,u)==0&&c.sticky==u.sticky)return o;var g=Me(p);if(!g)return o;var y=ee(g,c.ch,c.sticky),C=g[y];if(C.from!=c.ch&&C.to!=c.ch)return o;var _=y+(C.from==c.ch==(C.level!=1)?0:1);if(_==0||_==g.length)return o;var E;if(u.line!=c.line)E=(u.line-c.line)*(r.doc.direction=="ltr"?1:-1)>0;else{var O=ee(g,u.ch,u.sticky),F=O-y||(u.ch-c.ch)*(C.level==1?-1:1);O==_-1||O==_?E=F<0:E=F>0}var K=g[_+(E?-1:0)],V=E==(K.level==1),te=V?K.from:K.to,ae=V?"after":"before";return c.ch==te&&c.sticky==ae?o:new Et(new ce(c.line,te,ae),u)}i(Sd,"bidiSimplify");function bh(r,o,c,u){var p,g;if(o.touches)p=o.touches[0].clientX,g=o.touches[0].clientY;else try{p=o.clientX,g=o.clientY}catch{return!1}if(p>=Math.floor(r.display.gutters.getBoundingClientRect().right))return!1;u&&kr(o);var y=r.display,C=y.lineDiv.getBoundingClientRect();if(g>C.bottom||!dn(r,c))return bn(o);g-=C.top-y.viewOffset;for(var _=0;_=p){var O=ys(r.doc,g),F=r.display.gutterSpecs[_];return Mt(r,c,r,O,F.className,o),bn(o)}}}i(bh,"gutterEvent");function gu(r,o){return bh(r,o,"gutterClick",!0)}i(gu,"clickInGutter");function xd(r,o){yi(r.display,o)||Cd(r,o)||Pt(r,o,"contextmenu")||he||r.display.input.onContextMenu(o)}i(xd,"onContextMenu");function Cd(r,o){return dn(r,"gutterContextMenu")?bh(r,o,"gutterContextMenu",!1):!1}i(Cd,"contextMenuInGutter");function Xg(r){r.display.wrapper.className=r.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+r.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Vo(r)}i(Xg,"themeChanged");var rl={toString:i(function(){return"CodeMirror.Init"},"toString")},jc={},Kc={};function Th(r){var o=r.optionHandlers;function c(u,p,g,y){r.defaults[u]=p,g&&(o[u]=y?function(C,_,E){E!=rl&&g(C,_,E)}:g)}i(c,"option"),r.defineOption=c,r.Init=rl,c("value","",function(u,p){return u.setValue(p)},!0),c("mode",null,function(u,p){u.doc.modeOption=p,lh(u)},!0),c("indentUnit",2,lh,!0),c("indentWithTabs",!1),c("smartIndent",!0),c("tabSize",4,function(u){Ya(u),Vo(u),Wn(u)},!0),c("lineSeparator",null,function(u,p){if(u.doc.lineSep=p,!!p){var g=[],y=u.doc.first;u.doc.iter(function(_){for(var E=0;;){var O=_.text.indexOf(p,E);if(O==-1)break;E=O+p.length,g.push(ce(y,O))}y++});for(var C=g.length-1;C>=0;C--)Qa(u.doc,p,g[C],ce(g[C].line,g[C].ch+p.length))}}),c("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]/g,function(u,p,g){u.state.specialChars=new RegExp(p.source+(p.test(" ")?"":"| "),"g"),g!=rl&&u.refresh()}),c("specialCharPlaceholder",jt,function(u){return u.refresh()},!0),c("electricChars",!0),c("inputStyle",L?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),c("spellcheck",!1,function(u,p){return u.getInputField().spellcheck=p},!0),c("autocorrect",!1,function(u,p){return u.getInputField().autocorrect=p},!0),c("autocapitalize",!1,function(u,p){return u.getInputField().autocapitalize=p},!0),c("rtlMoveVisually",!re),c("wholeLineUpdateBefore",!0),c("theme","default",function(u){Xg(u),Rc(u)},!0),c("keyMap","default",function(u,p,g){var y=zc(p),C=g!=rl&&zc(g);C&&C.detach&&C.detach(u,y),y.attach&&y.attach(u,C||null)}),c("extraKeys",null),c("configureMouse",null),c("lineWrapping",!1,Qg,!0),c("gutters",[],function(u,p){u.display.gutterSpecs=yo(p,u.options.lineNumbers),Rc(u)},!0),c("fixedGutter",!0,function(u,p){u.display.gutters.style.left=p?kt(u.display)+"px":"0",u.refresh()},!0),c("coverGutterNextToScrollbar",!1,function(u){return Ko(u)},!0),c("scrollbarStyle","native",function(u){vg(u),Ko(u),u.display.scrollbars.setScrollTop(u.doc.scrollTop),u.display.scrollbars.setScrollLeft(u.doc.scrollLeft)},!0),c("lineNumbers",!1,function(u,p){u.display.gutterSpecs=yo(u.options.gutters,p),Rc(u)},!0),c("firstLineNumber",1,Rc,!0),c("lineNumberFormatter",function(u){return u},Rc,!0),c("showCursorWhenSelecting",!1,ra,!0),c("resetSelectionOnContextMenu",!0),c("lineWiseCopyCut",!0),c("pasteLinesPerSelection",!0),c("selectionsMayTouch",!1),c("readOnly",!1,function(u,p){p=="nocursor"&&(Jl(u),u.display.input.blur()),u.display.input.readOnlyChanged(p)}),c("screenReaderLabel",null,function(u,p){p=p===""?null:p,u.display.input.screenReaderLabelChanged(p)}),c("disableInput",!1,function(u,p){p||u.display.input.reset()},!0),c("dragDrop",!0,Dw),c("allowDropFileTypes",null),c("cursorBlinkRate",530),c("cursorScrollMargin",0),c("cursorHeight",1,ra,!0),c("singleCursorHeightPerLine",!0,ra,!0),c("workTime",100),c("workDelay",100),c("flattenSpans",!0,Ya,!0),c("addModeClass",!1,Ya,!0),c("pollInterval",100),c("undoDepth",200,function(u,p){return u.doc.history.undoDepth=p}),c("historyEventDelay",1250),c("viewportMargin",10,function(u){return u.refresh()},!0),c("maxHighlightLength",1e4,Ya,!0),c("moveInputWithCursor",!0,function(u,p){p||u.display.input.resetPosition()}),c("tabindex",null,function(u,p){return u.display.input.getField().tabIndex=p||""}),c("autofocus",null),c("direction","ltr",function(u,p){return u.doc.setDirection(p)},!0),c("phrases",null)}i(Th,"defineOptions");function Dw(r,o,c){var u=c&&c!=rl;if(!o!=!u){var p=r.display.dragFunctions,g=o?ze:Yt;g(r.display.scroller,"dragstart",p.start),g(r.display.scroller,"dragenter",p.enter),g(r.display.scroller,"dragover",p.over),g(r.display.scroller,"dragleave",p.leave),g(r.display.scroller,"drop",p.drop)}}i(Dw,"dragDropChanged");function Qg(r){r.options.lineWrapping?(It(r.display.wrapper,"CodeMirror-wrap"),r.display.sizer.style.minWidth="",r.display.sizerWidth=null):(Ee(r.display.wrapper,"CodeMirror-wrap"),Bl(r)),nd(r),Wn(r),Vo(r),setTimeout(function(){return Ko(r)},100)}i(Qg,"wrappingChanged");function wt(r,o){var c=this;if(!(this instanceof wt))return new wt(r,o);this.options=o=o?Gt(o):{},Gt(jc,o,!1);var u=o.value;typeof u=="string"?u=new kn(u,o.mode,null,o.lineSeparator,o.direction):o.mode&&(u.modeOption=o.mode),this.doc=u;var p=new wt.inputStyles[o.inputStyle](this),g=this.display=new xw(r,u,p,o);g.wrapper.CodeMirror=this,Xg(this),o.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),vg(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new se,keySeq:null,specialChars:null},o.autofocus&&!L&&g.input.focus(),d&&v<11&&setTimeout(function(){return c.display.input.reset(!0)},20),Jg(this),Wg(),Ka(this),this.curOp.forceUpdate=!0,uh(this,u),o.autofocus&&!L||this.hasFocus()?setTimeout(function(){c.hasFocus()&&!c.state.focused&&Zp(c)},20):Jl(this);for(var y in Kc)Kc.hasOwnProperty(y)&&Kc[y](this,o[y],rl);xg(this),o.finishInit&&o.finishInit(this);for(var C=0;C<_d.length;++C)_d[C](this);Ga(this),S&&o.lineWrapping&&getComputedStyle(g.lineDiv).textRendering=="optimizelegibility"&&(g.lineDiv.style.textRendering="auto")}i(wt,"CodeMirror"),wt.defaults=jc,wt.optionHandlers=Kc;function Jg(r){var o=r.display;ze(o.scroller,"mousedown",Lt(r,Kg)),d&&v<11?ze(o.scroller,"dblclick",Lt(r,function(_){if(!Pt(r,_)){var E=jo(r,_);if(!(!E||gu(r,_)||yi(r.display,_))){kr(_);var O=r.findWordAt(E);nu(r.doc,O.anchor,O.head)}}})):ze(o.scroller,"dblclick",function(_){return Pt(r,_)||kr(_)}),ze(o.scroller,"contextmenu",function(_){return xd(r,_)}),ze(o.input.getField(),"contextmenu",function(_){o.scroller.contains(_.target)||xd(r,_)});var c,u={end:0};function p(){o.activeTouch&&(c=setTimeout(function(){return o.activeTouch=null},1e3),u=o.activeTouch,u.end=+new Date)}i(p,"finishTouch");function g(_){if(_.touches.length!=1)return!1;var E=_.touches[0];return E.radiusX<=1&&E.radiusY<=1}i(g,"isMouseLikeTouchEvent");function y(_,E){if(E.left==null)return!0;var O=E.left-_.left,F=E.top-_.top;return O*O+F*F>20*20}i(y,"farAway"),ze(o.scroller,"touchstart",function(_){if(!Pt(r,_)&&!g(_)&&!gu(r,_)){o.input.ensurePolled(),clearTimeout(c);var E=+new Date;o.activeTouch={start:E,moved:!1,prev:E-u.end<=300?u:null},_.touches.length==1&&(o.activeTouch.left=_.touches[0].pageX,o.activeTouch.top=_.touches[0].pageY)}}),ze(o.scroller,"touchmove",function(){o.activeTouch&&(o.activeTouch.moved=!0)}),ze(o.scroller,"touchend",function(_){var E=o.activeTouch;if(E&&!yi(o,_)&&E.left!=null&&!E.moved&&new Date-E.start<300){var O=r.coordsChar(o.activeTouch,"page"),F;!E.prev||y(E,E.prev)?F=new Et(O,O):!E.prev.prev||y(E,E.prev.prev)?F=r.findWordAt(O):F=new Et(ce(O.line,0),qe(r.doc,ce(O.line+1,0))),r.setSelection(F.anchor,F.head),r.focus(),kr(_)}p()}),ze(o.scroller,"touchcancel",p),ze(o.scroller,"scroll",function(){o.scroller.clientHeight&&(Pc(r,o.scroller.scrollTop),go(r,o.scroller.scrollLeft,!0),Mt(r,"scroll",r))}),ze(o.scroller,"mousewheel",function(_){return _g(r,_)}),ze(o.scroller,"DOMMouseScroll",function(_){return _g(r,_)}),ze(o.wrapper,"scroll",function(){return o.wrapper.scrollTop=o.wrapper.scrollLeft=0}),o.dragFunctions={enter:i(function(_){Pt(r,_)||Aa(_)},"enter"),over:i(function(_){Pt(r,_)||(ut(r,_),Aa(_))},"over"),start:i(function(_){return yh(r,_)},"start"),drop:Lt(r,kw),leave:i(function(_){Pt(r,_)||zg(r)},"leave")};var C=o.input.getField();ze(C,"keyup",function(_){return Co.call(r,_)}),ze(C,"keydown",Lt(r,_h)),ze(C,"keypress",Lt(r,qg)),ze(C,"focus",function(_){return Zp(r,_)}),ze(C,"blur",function(_){return Jl(r,_)})}i(Jg,"registerEventHandlers");var _d=[];wt.defineInitHook=function(r){return _d.push(r)};function Gc(r,o,c,u){var p=r.doc,g;c==null&&(c="add"),c=="smart"&&(p.mode.indent?g=Ss(r,o).state:c="prev");var y=r.options.tabSize,C=Pe(p,o),_=Ft(C.text,null,y);C.stateAfter&&(C.stateAfter=null);var E=C.text.match(/^\s*/)[0],O;if(!u&&!/\S/.test(C.text))O=0,c="not";else if(c=="smart"&&(O=p.mode.indent(g,C.text.slice(E.length),C.text),O==Zt||O>150)){if(!u)return;c="prev"}c=="prev"?o>p.first?O=Ft(Pe(p,o-1).text,null,y):O=0:c=="add"?O=_+r.options.indentUnit:c=="subtract"?O=_-r.options.indentUnit:typeof c=="number"&&(O=_+c),O=Math.max(0,O);var F="",K=0;if(r.options.indentWithTabs)for(var V=Math.floor(O/y);V;--V)K+=y,F+=" ";if(Ky,_=kl(o),E=null;if(C&&u.ranges.length>1)if(Ui&&Ui.text.join(` +`)==o){if(u.ranges.length%Ui.text.length==0){E=[];for(var O=0;O=0;K--){var V=u.ranges[K],te=V.from(),ae=V.to();V.empty()&&(c&&c>0?te=ce(te.line,te.ch-c):r.state.overwrite&&!C?ae=ce(ae.line,Math.min(Pe(g,ae.line).text.length,ae.ch+lt(_).length)):C&&Ui&&Ui.lineWise&&Ui.text.join(` +`)==_.join(` +`)&&(te=ae=ce(te.line,0)));var de={from:te,to:ae,text:E?E[K%E.length]:_,origin:p||(C?"paste":r.state.cutIncoming>y?"cut":"+input")};au(r.doc,de),Kt(r,"inputRead",r,de)}o&&!C&&bd(r,o),er(r),r.curOp.updateInput<2&&(r.curOp.updateInput=F),r.curOp.typing=!0,r.state.pasteIncoming=r.state.cutIncoming=-1}i(kh,"applyTextInput");function Qo(r,o){var c=r.clipboardData&&r.clipboardData.getData("Text");if(c)return r.preventDefault(),!o.isReadOnly()&&!o.options.disableInput&&o.hasFocus()&&vn(o,function(){return kh(o,c,0,null,"paste")}),!0}i(Qo,"handlePaste");function bd(r,o){if(!(!r.options.electricChars||!r.options.smartIndent))for(var c=r.doc.sel,u=c.ranges.length-1;u>=0;u--){var p=c.ranges[u];if(!(p.head.ch>100||u&&c.ranges[u-1].head.line==p.head.line)){var g=r.getModeAt(p.head),y=!1;if(g.electricChars){for(var C=0;C-1){y=Gc(r,p.head.line,"smart");break}}else g.electricInput&&g.electricInput.test(Pe(r.doc,p.head.line).text.slice(0,p.head.ch))&&(y=Gc(r,p.head.line,"smart"));y&&Kt(r,"electricInput",r,p.head.line)}}}i(bd,"triggerElectric");function Td(r){for(var o=[],c=[],u=0;ug&&(Gc(this,C.head.line,u,!0),g=C.head.line,y==this.doc.sel.primIndex&&er(this));else{var _=C.from(),E=C.to(),O=Math.max(g,_.line);g=Math.min(this.lastLine(),E.line-(E.ch?0:1))+1;for(var F=O;F0&&zi(this.doc,y,new Et(_,K[y].to()),st)}}}),getTokenAt:i(function(u,p){return Rl(this,u,p)},"getTokenAt"),getLineTokens:i(function(u,p){return Rl(this,ce(u),p,!0)},"getLineTokens"),getTokenTypeAt:i(function(u){u=qe(this.doc,u);var p=Ml(this,Pe(this.doc,u.line)),g=0,y=(p.length-1)/2,C=u.ch,_;if(C==0)_=p[2];else for(;;){var E=g+y>>1;if((E?p[E*2-1]:0)>=C)y=E;else if(p[E*2+1]_&&(u=_,y=!0),C=Pe(this.doc,u)}else C=u;return gn(this,C,{top:0,left:0},p||"page",g||y).top+(y?this.doc.height-vi(C):0)},"heightAtLine"),defaultTextHeight:i(function(){return po(this.display)},"defaultTextHeight"),defaultCharWidth:i(function(){return Cs(this.display)},"defaultCharWidth"),getViewport:i(function(){return{from:this.display.viewFrom,to:this.display.viewTo}},"getViewport"),addWidget:i(function(u,p,g,y,C){var _=this.display;u=J(this,qe(this.doc,u));var E=u.bottom,O=u.left;if(p.style.position="absolute",p.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(p),_.sizer.appendChild(p),y=="over")E=u.top;else if(y=="above"||y=="near"){var F=Math.max(_.wrapper.clientHeight,this.doc.height),K=Math.max(_.sizer.clientWidth,_.lineSpace.clientWidth);(y=="above"||u.bottom+p.offsetHeight>F)&&u.top>p.offsetHeight?E=u.top-p.offsetHeight:u.bottom+p.offsetHeight<=F&&(E=u.bottom),O+p.offsetWidth>K&&(O=K-p.offsetWidth)}p.style.top=E+"px",p.style.left=p.style.right="",C=="right"?(O=_.sizer.clientWidth-p.offsetWidth,p.style.right="0px"):(C=="left"?O=0:C=="middle"&&(O=(_.sizer.clientWidth-p.offsetWidth)/2),p.style.left=O+"px"),g&&gg(this,{left:O,top:E,right:O+p.offsetWidth,bottom:E+p.offsetHeight})},"addWidget"),triggerOnKeyDown:$e(_h),triggerOnKeyPress:$e(qg),triggerOnKeyUp:Co,triggerOnMouseDown:$e(Kg),execCommand:i(function(u){if($c.hasOwnProperty(u))return $c[u].call(null,this)},"execCommand"),triggerElectric:$e(function(u){bd(this,u)}),findPosH:i(function(u,p,g,y){var C=1;p<0&&(C=-1,p=-p);for(var _=qe(this.doc,u),E=0;E0&&O(g.charAt(y-1));)--y;for(;C.5||this.options.lineWrapping)&&nd(this),Mt(this,"refresh",this)}),swapDoc:$e(function(u){var p=this.doc;return p.cm=null,this.state.selectingText&&this.state.selectingText(),uh(this,u),Vo(this),this.display.input.reset(),Ar(this,u.scrollLeft,u.scrollTop),this.curOp.forceScroll=!0,Kt(this,"swapDoc",this,p),p}),phrase:i(function(u){var p=this.options.phrases;return p&&Object.prototype.hasOwnProperty.call(p,u)?p[u]:u},"phrase"),getInputField:i(function(){return this.display.input.getField()},"getInputField"),getWrapperElement:i(function(){return this.display.wrapper},"getWrapperElement"),getScrollerElement:i(function(){return this.display.scroller},"getScrollerElement"),getGutterElement:i(function(){return this.display.gutters},"getGutterElement")},zn(r),r.registerHelper=function(u,p,g){c.hasOwnProperty(u)||(c[u]=r[u]={_global:[]}),c[u][p]=g},r.registerGlobalHelper=function(u,p,g,y){r.registerHelper(u,p,y),c[u]._global.push({pred:g,val:y})}}i(vu,"addEditorMethods");function We(r,o,c,u,p){var g=o,y=c,C=Pe(r,o.line),_=p&&r.direction=="rtl"?-c:c;function E(){var _e=o.line+_;return _e=r.first+r.size?!1:(o=new ce(_e,o.ch,o.sticky),C=Pe(r,_e))}i(E,"findNextLine");function O(_e){var ye;if(u=="codepoint"){var ke=C.text.charCodeAt(o.ch+(c>0?0:-1));if(isNaN(ke))ye=null;else{var Ie=c>0?ke>=55296&&ke<56320:ke>=56320&&ke<57343;ye=new ce(o.line,Math.max(0,Math.min(C.text.length,o.ch+c*(Ie?2:1))),-c)}}else p?ye=fa(r.cm,C,o,c):ye=Uc(C,o,c);if(ye==null)if(!_e&&E())o=Wc(p,r.cm,C,o.line,_);else return!1;else o=ye;return!0}if(i(O,"moveOnce"),u=="char"||u=="codepoint")O();else if(u=="column")O(!0);else if(u=="word"||u=="group")for(var F=null,K=u=="group",V=r.cm&&r.cm.getHelper(o,"wordChars"),te=!0;!(c<0&&!O(!te));te=!1){var ae=C.text.charAt(o.ch)||` +`,de=Gr(ae,V)?"w":K&&ae==` +`?"n":!K||/\s/.test(ae)?null:"p";if(K&&!te&&!de&&(de="s"),F&&F!=de){c<0&&(c=1,O(),o.sticky="after");break}if(de&&(F=de),c>0&&!O(!te))break}var we=ou(r,o,g,y,!0);return qs(g,we)&&(we.hitSide=!0),we}i(We,"findPosH");function Qc(r,o,c,u){var p=r.doc,g=o.left,y;if(u=="page"){var C=Math.min(r.display.wrapper.clientHeight,vr(r).innerHeight||p(r).documentElement.clientHeight),_=Math.max(C-.5*po(r.display),3);y=(c>0?o.bottom:o.top)+c*_}else u=="line"&&(y=c>0?o.bottom+3:o.top-3);for(var E;E=yt(r,g,y),!!E.outside;){if(c<0?y<=0:y>=p.height){E.hitSide=!0;break}y+=c*5}return E}i(Qc,"findPosV");var bt=i(function(r){this.cm=r,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new se,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null},"ContentEditableInput");bt.prototype.init=function(r){var o=this,c=this,u=c.cm,p=c.div=r.lineDiv;p.contentEditable=!0,Yc(p,u.options.spellcheck,u.options.autocorrect,u.options.autocapitalize);function g(C){for(var _=C.target;_;_=_.parentNode){if(_==p)return!0;if(/\bCodeMirror-(?:line)?widget\b/.test(_.className))break}return!1}i(g,"belongsToInput"),ze(p,"paste",function(C){!g(C)||Pt(u,C)||Qo(C,u)||v<=11&&setTimeout(Lt(u,function(){return o.updateFromDOM()}),20)}),ze(p,"compositionstart",function(C){o.composing={data:C.data,done:!1}}),ze(p,"compositionupdate",function(C){o.composing||(o.composing={data:C.data,done:!1})}),ze(p,"compositionend",function(C){o.composing&&(C.data!=o.composing.data&&o.readFromDOMSoon(),o.composing.done=!0)}),ze(p,"touchstart",function(){return c.forceCompositionEnd()}),ze(p,"input",function(){o.composing||o.readFromDOMSoon()});function y(C){if(!(!g(C)||Pt(u,C))){if(u.somethingSelected())Ed({lineWise:!1,text:u.getSelections()}),C.type=="cut"&&u.replaceSelection("",null,"cut");else if(u.options.lineWiseCopyCut){var _=Td(u);Ed({lineWise:!0,text:_.text}),C.type=="cut"&&u.operation(function(){u.setSelections(_.ranges,0,st),u.replaceSelection("",null,"cut")})}else return;if(C.clipboardData){C.clipboardData.clearData();var E=Ui.text.join(` +`);if(C.clipboardData.setData("Text",E),C.clipboardData.getData("Text")==E){C.preventDefault();return}}var O=Xc(),F=O.firstChild;Yc(F),u.display.lineSpace.insertBefore(O,u.display.lineSpace.firstChild),F.value=Ui.text.join(` +`);var K=ot(Wt(p));cn(F),setTimeout(function(){u.display.lineSpace.removeChild(O),K.focus(),K==p&&c.showPrimarySelection()},50)}}i(y,"onCopyCut"),ze(p,"copy",y),ze(p,"cut",y)},bt.prototype.screenReaderLabelChanged=function(r){r?this.div.setAttribute("aria-label",r):this.div.removeAttribute("aria-label")},bt.prototype.prepareSelection=function(){var r=Jp(this.cm,!1);return r.focus=ot(Wt(this.div))==this.div,r},bt.prototype.showSelection=function(r,o){!r||!this.cm.display.view.length||((r.focus||o)&&this.showPrimarySelection(),this.showMultipleSelections(r))},bt.prototype.getSelection=function(){return this.cm.display.wrapper.ownerDocument.getSelection()},bt.prototype.showPrimarySelection=function(){var r=this.getSelection(),o=this.cm,c=o.doc.sel.primary(),u=c.from(),p=c.to();if(o.display.viewTo==o.display.viewFrom||u.line>=o.display.viewTo||p.line=o.display.viewFrom&&da(o,u)||{node:C[0].measure.map[2],offset:0},E=p.liner.firstLine()&&(u=ce(u.line-1,Pe(r.doc,u.line-1).length)),p.ch==Pe(r.doc,p.line).text.length&&p.lineo.viewTo-1)return!1;var g,y,C;u.line==o.viewFrom||(g=Ua(r,u.line))==0?(y=vt(o.view[0].line),C=o.view[0].node):(y=vt(o.view[g].line),C=o.view[g-1].node.nextSibling);var _=Ua(r,p.line),E,O;if(_==o.view.length-1?(E=o.viewTo-1,O=o.lineDiv.lastChild):(E=vt(o.view[_+1].line)-1,O=o.view[_+1].node.previousSibling),!C)return!1;for(var F=r.doc.splitLines(Zg(r,C,O,y,E)),K=lo(r.doc,ce(y,0),ce(E,Pe(r.doc,E).text.length));F.length>1&&K.length>1;)if(lt(F)==lt(K))F.pop(),K.pop(),E--;else if(F[0]==K[0])F.shift(),K.shift(),y++;else break;for(var V=0,te=0,ae=F[0],de=K[0],we=Math.min(ae.length,de.length);Vu.ch&&_e.charCodeAt(_e.length-te-1)==ye.charCodeAt(ye.length-te-1);)V--,te++;F[F.length-1]=_e.slice(0,_e.length-te).replace(/^\u200b+/,""),F[0]=F[0].slice(V).replace(/\u200b+$/,"");var Ie=ce(y,V),Oe=ce(E,K.length?lt(K).length-te:0);if(F.length>1||F[0]||Ve(Ie,Oe))return Qa(r.doc,F,Ie,Oe,"+input"),!0},bt.prototype.ensurePolled=function(){this.forceCompositionEnd()},bt.prototype.reset=function(){this.forceCompositionEnd()},bt.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},bt.prototype.readFromDOMSoon=function(){var r=this;this.readDOMTimeout==null&&(this.readDOMTimeout=setTimeout(function(){if(r.readDOMTimeout=null,r.composing)if(r.composing.done)r.composing=null;else return;r.updateFromDOM()},80))},bt.prototype.updateFromDOM=function(){var r=this;(this.cm.isReadOnly()||!this.pollContent())&&vn(this.cm,function(){return Wn(r.cm)})},bt.prototype.setUneditable=function(r){r.contentEditable="false"},bt.prototype.onKeyPress=function(r){r.charCode==0||this.composing||(r.preventDefault(),this.cm.isReadOnly()||Lt(this.cm,kh)(this.cm,String.fromCharCode(r.charCode==null?r.keyCode:r.charCode),0))},bt.prototype.readOnlyChanged=function(r){this.div.contentEditable=String(r!="nocursor")},bt.prototype.onContextMenu=function(){},bt.prototype.resetPosition=function(){},bt.prototype.needsContentAttribute=!0;function da(r,o){var c=Gl(r,o.line);if(!c||c.hidden)return null;var u=Pe(r.doc,o.line),p=td(c,u,o.line),g=Me(u,r.doc.direction),y="left";if(g){var C=ee(g,o.ch);y=C%2?"right":"left"}var _=U(p.map,o.ch,y);return _.offset=_.collapse=="right"?_.end:_.start,_}i(da,"posToDOM");function Iw(r){for(var o=r;o;o=o.parentNode)if(/CodeMirror-gutter-wrapper/.test(o.className))return!0;return!1}i(Iw,"isInGutter");function pa(r,o){return o&&(r.bad=!0),r}i(pa,"badPos");function Zg(r,o,c,u,p){var g="",y=!1,C=r.doc.lineSeparator(),_=!1;function E(V){return function(te){return te.id==V}}i(E,"recognizeMarker");function O(){y&&(g+=C,_&&(g+=C),y=_=!1)}i(O,"close");function F(V){V&&(O(),g+=V)}i(F,"addText");function K(V){if(V.nodeType==1){var te=V.getAttribute("cm-text");if(te){F(te);return}var ae=V.getAttribute("cm-marker"),de;if(ae){var we=r.findMarks(ce(u,0),ce(p+1,0),E(+ae));we.length&&(de=we[0].find(0))&&F(lo(r.doc,de.from,de.to).join(C));return}if(V.getAttribute("contenteditable")=="false")return;var _e=/^(pre|div|p|li|table|br)$/i.test(V.nodeName);if(!/^br$/i.test(V.nodeName)&&V.textContent.length==0)return;_e&&O();for(var ye=0;ye=9&&o.hasSelection&&(o.hasSelection=null),c.poll()}),ze(p,"paste",function(y){Pt(u,y)||Qo(y,u)||(u.state.pasteIncoming=+new Date,c.fastPoll())});function g(y){if(!Pt(u,y)){if(u.somethingSelected())Ed({lineWise:!1,text:u.getSelections()});else if(u.options.lineWiseCopyCut){var C=Td(u);Ed({lineWise:!0,text:C.text}),y.type=="cut"?u.setSelections(C.ranges,null,st):(c.prevInput="",p.value=C.text.join(` +`),cn(p))}else return;y.type=="cut"&&(u.state.cutIncoming=+new Date)}}i(g,"prepareCopyCut"),ze(p,"cut",g),ze(p,"copy",g),ze(r.scroller,"paste",function(y){if(!(yi(r,y)||Pt(u,y))){if(!p.dispatchEvent){u.state.pasteIncoming=+new Date,c.focus();return}var C=new Event("paste");C.clipboardData=y.clipboardData,p.dispatchEvent(C)}}),ze(r.lineSpace,"selectstart",function(y){yi(r,y)||kr(y)}),ze(p,"compositionstart",function(){var y=u.getCursor("from");c.composing&&c.composing.range.clear(),c.composing={start:y,range:u.markText(y,u.getCursor("to"),{className:"CodeMirror-composing"})}}),ze(p,"compositionend",function(){c.composing&&(c.poll(),c.composing.range.clear(),c.composing=null)})},dr.prototype.createField=function(r){this.wrapper=Xc(),this.textarea=this.wrapper.firstChild;var o=this.cm.options;Yc(this.textarea,o.spellcheck,o.autocorrect,o.autocapitalize)},dr.prototype.screenReaderLabelChanged=function(r){r?this.textarea.setAttribute("aria-label",r):this.textarea.removeAttribute("aria-label")},dr.prototype.prepareSelection=function(){var r=this.cm,o=r.display,c=r.doc,u=Jp(r);if(r.options.moveInputWithCursor){var p=J(r,c.sel.primary().head,"div"),g=o.wrapper.getBoundingClientRect(),y=o.lineDiv.getBoundingClientRect();u.teTop=Math.max(0,Math.min(o.wrapper.clientHeight-10,p.top+y.top-g.top)),u.teLeft=Math.max(0,Math.min(o.wrapper.clientWidth-10,p.left+y.left-g.left))}return u},dr.prototype.showSelection=function(r){var o=this.cm,c=o.display;tt(c.cursorDiv,r.cursors),tt(c.selectionDiv,r.selection),r.teTop!=null&&(this.wrapper.style.top=r.teTop+"px",this.wrapper.style.left=r.teLeft+"px")},dr.prototype.reset=function(r){if(!(this.contextMenuPending||this.composing&&r)){var o=this.cm;if(this.resetting=!0,o.somethingSelected()){this.prevInput="";var c=o.getSelection();this.textarea.value=c,o.state.focused&&cn(this.textarea),d&&v>=9&&(this.hasSelection=c)}else r||(this.prevInput=this.textarea.value="",d&&v>=9&&(this.hasSelection=null));this.resetting=!1}},dr.prototype.getField=function(){return this.textarea},dr.prototype.supportsTouch=function(){return!1},dr.prototype.focus=function(){if(this.cm.options.readOnly!="nocursor"&&(!L||ot(Wt(this.textarea))!=this.textarea))try{this.textarea.focus()}catch{}},dr.prototype.blur=function(){this.textarea.blur()},dr.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},dr.prototype.receivedFocus=function(){this.slowPoll()},dr.prototype.slowPoll=function(){var r=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){r.poll(),r.cm.state.focused&&r.slowPoll()})},dr.prototype.fastPoll=function(){var r=!1,o=this;o.pollingFast=!0;function c(){var u=o.poll();!u&&!r?(r=!0,o.polling.set(60,c)):(o.pollingFast=!1,o.slowPoll())}i(c,"p"),o.polling.set(20,c)},dr.prototype.poll=function(){var r=this,o=this.cm,c=this.textarea,u=this.prevInput;if(this.contextMenuPending||this.resetting||!o.state.focused||Bp(c)&&!u&&!this.composing||o.isReadOnly()||o.options.disableInput||o.state.keySeq)return!1;var p=c.value;if(p==u&&!o.somethingSelected())return!1;if(d&&v>=9&&this.hasSelection===p||B&&/[\uf700-\uf7ff]/.test(p))return o.display.input.reset(),!1;if(o.doc.sel==o.display.selForContextMenu){var g=p.charCodeAt(0);if(g==8203&&!u&&(u="\u200B"),g==8666)return this.reset(),this.cm.execCommand("undo")}for(var y=0,C=Math.min(u.length,p.length);y1e3||p.indexOf(` +`)>-1?c.value=r.prevInput="":r.prevInput=p,r.composing&&(r.composing.range.clear(),r.composing.range=o.markText(r.composing.start,o.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},dr.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},dr.prototype.onKeyPress=function(){d&&v>=9&&(this.hasSelection=null),this.fastPoll()},dr.prototype.onContextMenu=function(r){var o=this,c=o.cm,u=c.display,p=o.textarea;o.contextMenuPending&&o.contextMenuPending();var g=jo(c,r),y=u.scroller.scrollTop;if(!g||I)return;var C=c.options.resetSelectionOnContextMenu;C&&c.doc.sel.contains(g)==-1&&Lt(c,Jr)(c.doc,oa(g),st);var _=p.style.cssText,E=o.wrapper.style.cssText,O=o.wrapper.offsetParent.getBoundingClientRect();o.wrapper.style.cssText="position: static",p.style.cssText=`position: absolute; width: 30px; height: 30px; + top: `+(r.clientY-O.top-5)+"px; left: "+(r.clientX-O.left-5)+`px; + z-index: 1000; background: `+(d?"rgba(255, 255, 255, .05)":"transparent")+`; + outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);`;var F;S&&(F=p.ownerDocument.defaultView.scrollY),u.input.focus(),S&&p.ownerDocument.defaultView.scrollTo(null,F),u.input.reset(),c.somethingSelected()||(p.value=o.prevInput=" "),o.contextMenuPending=V,u.selForContextMenu=c.doc.sel,clearTimeout(u.detectingSelectAll);function K(){if(p.selectionStart!=null){var ae=c.somethingSelected(),de="\u200B"+(ae?p.value:"");p.value="\u21DA",p.value=de,o.prevInput=ae?"":"\u200B",p.selectionStart=1,p.selectionEnd=de.length,u.selForContextMenu=c.doc.sel}}i(K,"prepareSelectAllHack");function V(){if(o.contextMenuPending==V&&(o.contextMenuPending=!1,o.wrapper.style.cssText=E,p.style.cssText=_,d&&v<9&&u.scrollbars.setScrollTop(u.scroller.scrollTop=y),p.selectionStart!=null)){(!d||d&&v<9)&&K();var ae=0,de=i(function(){u.selForContextMenu==c.doc.sel&&p.selectionStart==0&&p.selectionEnd>0&&o.prevInput=="\u200B"?Lt(c,su)(c):ae++<10?u.detectingSelectAll=setTimeout(de,500):(u.selForContextMenu=null,u.input.reset())},"poll");u.detectingSelectAll=setTimeout(de,200)}}if(i(V,"rehide"),d&&v>=9&&K(),he){Aa(r);var te=i(function(){Yt(window,"mouseup",te),setTimeout(V,20)},"mouseup");ze(window,"mouseup",te)}else setTimeout(V,50)},dr.prototype.readOnlyChanged=function(r){r||this.reset(),this.textarea.disabled=r=="nocursor",this.textarea.readOnly=!!r},dr.prototype.setUneditable=function(){},dr.prototype.needsContentAttribute=!1;function ev(r,o){if(o=o?Gt(o):{},o.value=r.value,!o.tabindex&&r.tabIndex&&(o.tabindex=r.tabIndex),!o.placeholder&&r.placeholder&&(o.placeholder=r.placeholder),o.autofocus==null){var c=ot(Wt(r));o.autofocus=c==r||r.getAttribute("autofocus")!=null&&c==document.body}function u(){r.value=C.getValue()}i(u,"save");var p;if(r.form&&(ze(r.form,"submit",u),!o.leaveSubmitMethodAlone)){var g=r.form;p=g.submit;try{var y=g.submit=function(){u(),g.submit=p,g.submit(),g.submit=y}}catch{}}o.finishInit=function(_){_.save=u,_.getTextArea=function(){return r},_.toTextArea=function(){_.toTextArea=isNaN,u(),r.parentNode.removeChild(_.getWrapperElement()),r.style.display="",r.form&&(Yt(r.form,"submit",u),!o.leaveSubmitMethodAlone&&typeof r.form.submit=="function"&&(r.form.submit=p))}},r.style.display="none";var C=wt(function(_){return r.parentNode.insertBefore(_,r.nextSibling)},o);return C}i(ev,"fromTextArea");function Bw(r){r.off=Yt,r.on=ze,r.wheelEventPixels=Cw,r.Doc=kn,r.splitLines=kl,r.countColumn=Ft,r.findColumn=En,r.isWordChar=Mi,r.Pass=Zt,r.signal=Mt,r.Line=pn,r.changeEnd=sa,r.scrollbarModel=ja,r.Pos=ce,r.cmpPos=Ve,r.modes=ac,r.mimeModes=vs,r.resolveMode=La,r.getMode=lc,r.modeExtensions=ao,r.extendMode=qf,r.copyState=Oi,r.startState=cc,r.innerMode=uc,r.commands=$c,r.keyMap=Yo,r.keyName=Hc,r.isModifierKey=vd,r.lookupKey=xi,r.normalizeKeyMap=Si,r.StringStream=or,r.SharedTextMarker=cu,r.TextMarker=xo,r.LineWidget=Za,r.e_preventDefault=kr,r.e_stopPropagation=gs,r.e_stop=Aa,r.addClass=It,r.contains=Qe,r.rmClass=Ee,r.keyNames=Br}i(Bw,"addLegacyProps"),Th(wt),vu(wt);var tv="iter insert remove copy getEditor constructor".split(" ");for(var kd in kn.prototype)kn.prototype.hasOwnProperty(kd)&&Ue(tv,kd)<0&&(wt.prototype[kd]=function(r){return function(){return r.apply(this.doc,arguments)}}(kn.prototype[kd]));return zn(kn),wt.inputStyles={textarea:dr,contenteditable:bt},wt.defineMode=function(r){!wt.defaults.mode&&r!="null"&&(wt.defaults.mode=r),zp.apply(this,arguments)},wt.defineMIME=Up,wt.defineMode("null",function(){return{token:i(function(r){return r.skipToEnd()},"token")}}),wt.defineMIME("text/plain","null"),wt.defineExtension=function(r,o){wt.prototype[r]=o},wt.defineDocExtension=function(r,o){kn.prototype[r]=o},wt.fromTextArea=ev,Bw(wt),wt.version="5.65.16",wt})});var HL=rt((IK,BL)=>{var Dz=typeof Element<"u",Iz=typeof Map=="function",Fz=typeof Set=="function",Bz=typeof ArrayBuffer=="function"&&!!ArrayBuffer.isView;function O0(e,t){if(e===t)return!0;if(e&&t&&typeof e=="object"&&typeof t=="object"){if(e.constructor!==t.constructor)return!1;var n,s,l;if(Array.isArray(e)){if(n=e.length,n!=t.length)return!1;for(s=n;s--!==0;)if(!O0(e[s],t[s]))return!1;return!0}var h;if(Iz&&e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(h=e.entries();!(s=h.next()).done;)if(!t.has(s.value[0]))return!1;for(h=e.entries();!(s=h.next()).done;)if(!O0(s.value[1],t.get(s.value[0])))return!1;return!0}if(Fz&&e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;for(h=e.entries();!(s=h.next()).done;)if(!t.has(s.value[0]))return!1;return!0}if(Bz&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(t)){if(n=e.length,n!=t.length)return!1;for(s=n;s--!==0;)if(e[s]!==t[s])return!1;return!0}if(e.constructor===RegExp)return e.source===t.source&&e.flags===t.flags;if(e.valueOf!==Object.prototype.valueOf&&typeof e.valueOf=="function"&&typeof t.valueOf=="function")return e.valueOf()===t.valueOf();if(e.toString!==Object.prototype.toString&&typeof e.toString=="function"&&typeof t.toString=="function")return e.toString()===t.toString();if(l=Object.keys(e),n=l.length,n!==Object.keys(t).length)return!1;for(s=n;s--!==0;)if(!Object.prototype.hasOwnProperty.call(t,l[s]))return!1;if(Dz&&e instanceof Element)return!1;for(s=n;s--!==0;)if(!((l[s]==="_owner"||l[s]==="__v"||l[s]==="__o")&&e.$$typeof)&&!O0(e[l[s]],t[l[s]]))return!1;return!0}return e!==e&&t!==t}i(O0,"equal");BL.exports=i(function(t,n){try{return O0(t,n)}catch(s){if((s.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw s}},"isEqual")});var oM=rt((qY,iM)=>{iM.exports=function(){return typeof Promise=="function"&&Promise.prototype&&Promise.prototype.then}});var Qu=rt(Ff=>{var $_,Jz=[0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706];Ff.getSymbolSize=i(function(t){if(!t)throw new Error('"version" cannot be null or undefined');if(t<1||t>40)throw new Error('"version" should be in range from 1 to 40');return t*4+17},"getSymbolSize");Ff.getSymbolTotalCodewords=i(function(t){return Jz[t]},"getSymbolTotalCodewords");Ff.getBCHDigit=function(e){let t=0;for(;e!==0;)t++,e>>>=1;return t};Ff.setToSJISFunction=i(function(t){if(typeof t!="function")throw new Error('"toSJISFunc" is not a valid function.');$_=t},"setToSJISFunction");Ff.isKanjiModeEnabled=function(){return typeof $_<"u"};Ff.toSJIS=i(function(t){return $_(t)},"toSJIS")});var V0=rt(ps=>{ps.L={bit:1};ps.M={bit:0};ps.Q={bit:3};ps.H={bit:2};function Zz(e){if(typeof e!="string")throw new Error("Param is not a string");switch(e.toLowerCase()){case"l":case"low":return ps.L;case"m":case"medium":return ps.M;case"q":case"quartile":return ps.Q;case"h":case"high":return ps.H;default:throw new Error("Unknown EC Level: "+e)}}i(Zz,"fromString");ps.isValid=i(function(t){return t&&typeof t.bit<"u"&&t.bit>=0&&t.bit<4},"isValid");ps.from=i(function(t,n){if(ps.isValid(t))return t;try{return Zz(t)}catch{return n}},"from")});var lM=rt((XY,aM)=>{function sM(){this.buffer=[],this.length=0}i(sM,"BitBuffer");sM.prototype={get:i(function(e){let t=Math.floor(e/8);return(this.buffer[t]>>>7-e%8&1)===1},"get"),put:i(function(e,t){for(let n=0;n>>t-n-1&1)===1)},"put"),getLengthInBits:i(function(){return this.length},"getLengthInBits"),putBit:i(function(e){let t=Math.floor(this.length/8);this.buffer.length<=t&&this.buffer.push(0),e&&(this.buffer[t]|=128>>>this.length%8),this.length++},"putBit")};aM.exports=sM});var cM=rt((JY,uM)=>{function tg(e){if(!e||e<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=e,this.data=new Uint8Array(e*e),this.reservedBit=new Uint8Array(e*e)}i(tg,"BitMatrix");tg.prototype.set=function(e,t,n,s){let l=e*this.size+t;this.data[l]=n,s&&(this.reservedBit[l]=!0)};tg.prototype.get=function(e,t){return this.data[e*this.size+t]};tg.prototype.xor=function(e,t,n){this.data[e*this.size+t]^=n};tg.prototype.isReserved=function(e,t){return this.reservedBit[e*this.size+t]};uM.exports=tg});var fM=rt(q0=>{var eU=Qu().getSymbolSize;q0.getRowColCoords=i(function(t){if(t===1)return[];let n=Math.floor(t/7)+2,s=eU(t),l=s===145?26:Math.ceil((s-13)/(2*n-2))*2,h=[s-7];for(let d=1;d{var tU=Qu().getSymbolSize,dM=7;pM.getPositions=i(function(t){let n=tU(t);return[[0,0],[n-dM,0],[0,n-dM]]},"getPositions")});var mM=rt(ir=>{ir.Patterns={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var Bf={N1:3,N2:3,N3:40,N4:10};ir.isValid=i(function(t){return t!=null&&t!==""&&!isNaN(t)&&t>=0&&t<=7},"isValid");ir.from=i(function(t){return ir.isValid(t)?parseInt(t,10):void 0},"from");ir.getPenaltyN1=i(function(t){let n=t.size,s=0,l=0,h=0,d=null,v=null;for(let S=0;S=5&&(s+=Bf.N1+(l-5)),d=k,l=1),k=t.get(b,S),k===v?h++:(h>=5&&(s+=Bf.N1+(h-5)),v=k,h=1)}l>=5&&(s+=Bf.N1+(l-5)),h>=5&&(s+=Bf.N1+(h-5))}return s},"getPenaltyN1");ir.getPenaltyN2=i(function(t){let n=t.size,s=0;for(let l=0;l=10&&(l===1488||l===93)&&s++,h=h<<1&2047|t.get(v,d),v>=10&&(h===1488||h===93)&&s++}return s*Bf.N3},"getPenaltyN3");ir.getPenaltyN4=i(function(t){let n=0,s=t.data.length;for(let h=0;h{var Ju=V0(),j0=[1,1,1,1,1,1,1,1,1,1,2,2,1,2,2,4,1,2,4,4,2,4,4,4,2,4,6,5,2,4,6,6,2,5,8,8,4,5,8,8,4,5,8,11,4,8,10,11,4,9,12,16,4,9,16,16,6,10,12,18,6,10,17,16,6,11,16,19,6,13,18,21,7,14,21,25,8,16,20,25,8,17,23,25,9,17,23,34,9,18,25,30,10,20,27,32,12,21,29,35,12,23,34,37,12,25,34,40,13,26,35,42,14,28,38,45,15,29,40,48,16,31,43,51,17,33,45,54,18,35,48,57,19,37,51,60,19,38,53,63,20,40,56,66,21,43,59,70,22,45,62,74,24,47,65,77,25,49,68,81],K0=[7,10,13,17,10,16,22,28,15,26,36,44,20,36,52,64,26,48,72,88,36,64,96,112,40,72,108,130,48,88,132,156,60,110,160,192,72,130,192,224,80,150,224,264,96,176,260,308,104,198,288,352,120,216,320,384,132,240,360,432,144,280,408,480,168,308,448,532,180,338,504,588,196,364,546,650,224,416,600,700,224,442,644,750,252,476,690,816,270,504,750,900,300,560,810,960,312,588,870,1050,336,644,952,1110,360,700,1020,1200,390,728,1050,1260,420,784,1140,1350,450,812,1200,1440,480,868,1290,1530,510,924,1350,1620,540,980,1440,1710,570,1036,1530,1800,570,1064,1590,1890,600,1120,1680,1980,630,1204,1770,2100,660,1260,1860,2220,720,1316,1950,2310,750,1372,2040,2430];V_.getBlocksCount=i(function(t,n){switch(n){case Ju.L:return j0[(t-1)*4+0];case Ju.M:return j0[(t-1)*4+1];case Ju.Q:return j0[(t-1)*4+2];case Ju.H:return j0[(t-1)*4+3];default:return}},"getBlocksCount");V_.getTotalCodewordsCount=i(function(t,n){switch(n){case Ju.L:return K0[(t-1)*4+0];case Ju.M:return K0[(t-1)*4+1];case Ju.Q:return K0[(t-1)*4+2];case Ju.H:return K0[(t-1)*4+3];default:return}},"getTotalCodewordsCount")});var gM=rt(Y0=>{var rg=new Uint8Array(512),G0=new Uint8Array(256);i(function(){let t=1;for(let n=0;n<255;n++)rg[n]=t,G0[t]=n,t<<=1,t&256&&(t^=285);for(let n=255;n<512;n++)rg[n]=rg[n-255]},"initTables")();Y0.log=i(function(t){if(t<1)throw new Error("log("+t+")");return G0[t]},"log");Y0.exp=i(function(t){return rg[t]},"exp");Y0.mul=i(function(t,n){return t===0||n===0?0:rg[G0[t]+G0[n]]},"mul")});var vM=rt(ng=>{var j_=gM();ng.mul=i(function(t,n){let s=new Uint8Array(t.length+n.length-1);for(let l=0;l=0;){let l=s[0];for(let d=0;d{var yM=vM();function K_(e){this.genPoly=void 0,this.degree=e,this.degree&&this.initialize(this.degree)}i(K_,"ReedSolomonEncoder");K_.prototype.initialize=i(function(t){this.degree=t,this.genPoly=yM.generateECPolynomial(this.degree)},"initialize");K_.prototype.encode=i(function(t){if(!this.genPoly)throw new Error("Encoder not initialized");let n=new Uint8Array(t.length+this.degree);n.set(t);let s=yM.mod(n,this.genPoly),l=this.degree-s.length;if(l>0){let h=new Uint8Array(this.degree);return h.set(s,l),h}return s},"encode");wM.exports=K_});var G_=rt(xM=>{xM.isValid=i(function(t){return!isNaN(t)&&t>=1&&t<=40},"isValid")});var Y_=rt(_l=>{var CM="[0-9]+",nU="[A-Z $%*+\\-./:]+",ig="(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";ig=ig.replace(/u/g,"\\u");var iU="(?:(?![A-Z0-9 $%*+\\-./:]|"+ig+`)(?:.|[\r +]))+`;_l.KANJI=new RegExp(ig,"g");_l.BYTE_KANJI=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g");_l.BYTE=new RegExp(iU,"g");_l.NUMERIC=new RegExp(CM,"g");_l.ALPHANUMERIC=new RegExp(nU,"g");var oU=new RegExp("^"+ig+"$"),sU=new RegExp("^"+CM+"$"),aU=new RegExp("^[A-Z0-9 $%*+\\-./:]+$");_l.testKanji=i(function(t){return oU.test(t)},"testKanji");_l.testNumeric=i(function(t){return sU.test(t)},"testNumeric");_l.testAlphanumeric=i(function(t){return aU.test(t)},"testAlphanumeric")});var Zu=rt(sn=>{var lU=G_(),X_=Y_();sn.NUMERIC={id:"Numeric",bit:1,ccBits:[10,12,14]};sn.ALPHANUMERIC={id:"Alphanumeric",bit:2,ccBits:[9,11,13]};sn.BYTE={id:"Byte",bit:4,ccBits:[8,16,16]};sn.KANJI={id:"Kanji",bit:8,ccBits:[8,10,12]};sn.MIXED={bit:-1};sn.getCharCountIndicator=i(function(t,n){if(!t.ccBits)throw new Error("Invalid mode: "+t);if(!lU.isValid(n))throw new Error("Invalid version: "+n);return n>=1&&n<10?t.ccBits[0]:n<27?t.ccBits[1]:t.ccBits[2]},"getCharCountIndicator");sn.getBestModeForData=i(function(t){return X_.testNumeric(t)?sn.NUMERIC:X_.testAlphanumeric(t)?sn.ALPHANUMERIC:X_.testKanji(t)?sn.KANJI:sn.BYTE},"getBestModeForData");sn.toString=i(function(t){if(t&&t.id)return t.id;throw new Error("Invalid mode")},"toString");sn.isValid=i(function(t){return t&&t.bit&&t.ccBits},"isValid");function uU(e){if(typeof e!="string")throw new Error("Param is not a string");switch(e.toLowerCase()){case"numeric":return sn.NUMERIC;case"alphanumeric":return sn.ALPHANUMERIC;case"kanji":return sn.KANJI;case"byte":return sn.BYTE;default:throw new Error("Unknown mode: "+e)}}i(uU,"fromString");sn.from=i(function(t,n){if(sn.isValid(t))return t;try{return uU(t)}catch{return n}},"from")});var kM=rt(Hf=>{var X0=Qu(),cU=q_(),_M=V0(),ec=Zu(),Q_=G_(),bM=7973,EM=X0.getBCHDigit(bM);function fU(e,t,n){for(let s=1;s<=40;s++)if(t<=Hf.getCapacity(s,n,e))return s}i(fU,"getBestVersionForDataLength");function TM(e,t){return ec.getCharCountIndicator(e,t)+4}i(TM,"getReservedBitsCount");function dU(e,t){let n=0;return e.forEach(function(s){let l=TM(s.mode,t);n+=l+s.getBitsLength()}),n}i(dU,"getTotalBitsFromDataArray");function pU(e,t){for(let n=1;n<=40;n++)if(dU(e,n)<=Hf.getCapacity(n,t,ec.MIXED))return n}i(pU,"getBestVersionForMixedData");Hf.from=i(function(t,n){return Q_.isValid(t)?parseInt(t,10):n},"from");Hf.getCapacity=i(function(t,n,s){if(!Q_.isValid(t))throw new Error("Invalid QR Code version");typeof s>"u"&&(s=ec.BYTE);let l=X0.getSymbolTotalCodewords(t),h=cU.getTotalCodewordsCount(t,n),d=(l-h)*8;if(s===ec.MIXED)return d;let v=d-TM(s,t);switch(s){case ec.NUMERIC:return Math.floor(v/10*3);case ec.ALPHANUMERIC:return Math.floor(v/11*2);case ec.KANJI:return Math.floor(v/13);case ec.BYTE:default:return Math.floor(v/8)}},"getCapacity");Hf.getBestVersionForData=i(function(t,n){let s,l=_M.from(n,_M.M);if(Array.isArray(t)){if(t.length>1)return pU(t,l);if(t.length===0)return 1;s=t[0]}else s=t;return fU(s.mode,s.getLength(),l)},"getBestVersionForData");Hf.getEncodedBits=i(function(t){if(!Q_.isValid(t)||t<7)throw new Error("Invalid QR Code version");let n=t<<12;for(;X0.getBCHDigit(n)-EM>=0;)n^=bM<{var J_=Qu(),AM=1335,hU=21522,NM=J_.getBCHDigit(AM);PM.getEncodedBits=i(function(t,n){let s=t.bit<<3|n,l=s<<10;for(;J_.getBCHDigit(l)-NM>=0;)l^=AM<{var mU=Zu();function Ap(e){this.mode=mU.NUMERIC,this.data=e.toString()}i(Ap,"NumericData");Ap.getBitsLength=i(function(t){return 10*Math.floor(t/3)+(t%3?t%3*3+1:0)},"getBitsLength");Ap.prototype.getLength=i(function(){return this.data.length},"getLength");Ap.prototype.getBitsLength=i(function(){return Ap.getBitsLength(this.data.length)},"getBitsLength");Ap.prototype.write=i(function(t){let n,s,l;for(n=0;n+3<=this.data.length;n+=3)s=this.data.substr(n,3),l=parseInt(s,10),t.put(l,10);let h=this.data.length-n;h>0&&(s=this.data.substr(n),l=parseInt(s,10),t.put(l,h*3+1))},"write");MM.exports=Ap});var DM=rt((TX,RM)=>{var gU=Zu(),Z_=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"," ","$","%","*","+","-",".","/",":"];function Pp(e){this.mode=gU.ALPHANUMERIC,this.data=e}i(Pp,"AlphanumericData");Pp.getBitsLength=i(function(t){return 11*Math.floor(t/2)+6*(t%2)},"getBitsLength");Pp.prototype.getLength=i(function(){return this.data.length},"getLength");Pp.prototype.getBitsLength=i(function(){return Pp.getBitsLength(this.data.length)},"getBitsLength");Pp.prototype.write=i(function(t){let n;for(n=0;n+2<=this.data.length;n+=2){let s=Z_.indexOf(this.data[n])*45;s+=Z_.indexOf(this.data[n+1]),t.put(s,11)}this.data.length%2&&t.put(Z_.indexOf(this.data[n]),6)},"write");RM.exports=Pp});var FM=rt((NX,IM)=>{"use strict";IM.exports=i(function(t){for(var n=[],s=t.length,l=0;l=55296&&h<=56319&&s>l+1){var d=t.charCodeAt(l+1);d>=56320&&d<=57343&&(h=(h-55296)*1024+d-56320+65536,l+=1)}if(h<128){n.push(h);continue}if(h<2048){n.push(h>>6|192),n.push(h&63|128);continue}if(h<55296||h>=57344&&h<65536){n.push(h>>12|224),n.push(h>>6&63|128),n.push(h&63|128);continue}if(h>=65536&&h<=1114111){n.push(h>>18|240),n.push(h>>12&63|128),n.push(h>>6&63|128),n.push(h&63|128);continue}n.push(239,191,189)}return new Uint8Array(n).buffer},"encodeUtf8")});var HM=rt((PX,BM)=>{var vU=FM(),yU=Zu();function Lp(e){this.mode=yU.BYTE,typeof e=="string"&&(e=vU(e)),this.data=new Uint8Array(e)}i(Lp,"ByteData");Lp.getBitsLength=i(function(t){return t*8},"getBitsLength");Lp.prototype.getLength=i(function(){return this.data.length},"getLength");Lp.prototype.getBitsLength=i(function(){return Lp.getBitsLength(this.data.length)},"getBitsLength");Lp.prototype.write=function(e){for(let t=0,n=this.data.length;t{var wU=Zu(),SU=Qu();function Mp(e){this.mode=wU.KANJI,this.data=e}i(Mp,"KanjiData");Mp.getBitsLength=i(function(t){return t*13},"getBitsLength");Mp.prototype.getLength=i(function(){return this.data.length},"getLength");Mp.prototype.getBitsLength=i(function(){return Mp.getBitsLength(this.data.length)},"getBitsLength");Mp.prototype.write=function(e){let t;for(t=0;t=33088&&n<=40956)n-=33088;else if(n>=57408&&n<=60351)n-=49472;else throw new Error("Invalid SJIS character: "+this.data[t]+` +Make sure your charset is UTF-8`);n=(n>>>8&255)*192+(n&255),e.put(n,13)}};zM.exports=Mp});var WM=rt((RX,eE)=>{"use strict";var og={single_source_shortest_paths:i(function(e,t,n){var s={},l={};l[t]=0;var h=og.PriorityQueue.make();h.push(t,0);for(var d,v,S,b,k,R,I,z,q;!h.empty();){d=h.pop(),v=d.value,b=d.cost,k=e[v]||{};for(S in k)k.hasOwnProperty(S)&&(R=k[S],I=b+R,z=l[S],q=typeof l[S]>"u",(q||z>I)&&(l[S]=I,h.push(S,I),s[S]=v))}if(typeof n<"u"&&typeof l[n]>"u"){var Q=["Could not find a path from ",t," to ",n,"."].join("");throw new Error(Q)}return s},"single_source_shortest_paths"),extract_shortest_path_from_predecessor_list:i(function(e,t){for(var n=[],s=t,l;s;)n.push(s),l=e[s],s=e[s];return n.reverse(),n},"extract_shortest_path_from_predecessor_list"),find_path:i(function(e,t,n){var s=og.single_source_shortest_paths(e,t,n);return og.extract_shortest_path_from_predecessor_list(s,n)},"find_path"),PriorityQueue:{make:i(function(e){var t=og.PriorityQueue,n={},s;e=e||{};for(s in t)t.hasOwnProperty(s)&&(n[s]=t[s]);return n.queue=[],n.sorter=e.sorter||t.default_sorter,n},"make"),default_sorter:i(function(e,t){return e.cost-t.cost},"default_sorter"),push:i(function(e,t){var n={value:e,cost:t};this.queue.push(n),this.queue.sort(this.sorter)},"push"),pop:i(function(){return this.queue.shift()},"pop"),empty:i(function(){return this.queue.length===0},"empty")}};typeof eE<"u"&&(eE.exports=og)});var XM=rt(Op=>{var Ut=Zu(),qM=OM(),jM=DM(),KM=HM(),GM=UM(),sg=Y_(),Q0=Qu(),xU=WM();function $M(e){return unescape(encodeURIComponent(e)).length}i($M,"getStringByteLength");function ag(e,t,n){let s=[],l;for(;(l=e.exec(n))!==null;)s.push({data:l[0],index:l.index,mode:t,length:l[0].length});return s}i(ag,"getSegments");function YM(e){let t=ag(sg.NUMERIC,Ut.NUMERIC,e),n=ag(sg.ALPHANUMERIC,Ut.ALPHANUMERIC,e),s,l;return Q0.isKanjiModeEnabled()?(s=ag(sg.BYTE,Ut.BYTE,e),l=ag(sg.KANJI,Ut.KANJI,e)):(s=ag(sg.BYTE_KANJI,Ut.BYTE,e),l=[]),t.concat(n,s,l).sort(function(d,v){return d.index-v.index}).map(function(d){return{data:d.data,mode:d.mode,length:d.length}})}i(YM,"getSegmentsFromString");function tE(e,t){switch(t){case Ut.NUMERIC:return qM.getBitsLength(e);case Ut.ALPHANUMERIC:return jM.getBitsLength(e);case Ut.KANJI:return GM.getBitsLength(e);case Ut.BYTE:return KM.getBitsLength(e)}}i(tE,"getSegmentBitsLength");function CU(e){return e.reduce(function(t,n){let s=t.length-1>=0?t[t.length-1]:null;return s&&s.mode===n.mode?(t[t.length-1].data+=n.data,t):(t.push(n),t)},[])}i(CU,"mergeSegments");function _U(e){let t=[];for(let n=0;n{var Z0=Qu(),rE=V0(),bU=lM(),TU=cM(),kU=fM(),NU=hM(),oE=mM(),sE=q_(),AU=SM(),J0=kM(),PU=LM(),LU=Zu(),nE=XM();function MU(e,t){let n=e.size,s=NU.getPositions(t);for(let l=0;l=0&&v<=6&&(S===0||S===6)||S>=0&&S<=6&&(v===0||v===6)||v>=2&&v<=4&&S>=2&&S<=4?e.set(h+v,d+S,!0,!0):e.set(h+v,d+S,!1,!0))}}i(MU,"setupFinderPattern");function OU(e){let t=e.size;for(let n=8;n>v&1)===1,e.set(l,h,d,!0),e.set(h,l,d,!0)}i(DU,"setupVersionInfo");function iE(e,t,n){let s=e.size,l=PU.getEncodedBits(t,n),h,d;for(h=0;h<15;h++)d=(l>>h&1)===1,h<6?e.set(h,8,d,!0):h<8?e.set(h+1,8,d,!0):e.set(s-15+h,8,d,!0),h<8?e.set(8,s-h-1,d,!0):h<9?e.set(8,15-h-1+1,d,!0):e.set(8,15-h-1,d,!0);e.set(s-8,8,1,!0)}i(iE,"setupFormatInfo");function IU(e,t){let n=e.size,s=-1,l=n-1,h=7,d=0;for(let v=n-1;v>0;v-=2)for(v===6&&v--;;){for(let S=0;S<2;S++)if(!e.isReserved(l,v-S)){let b=!1;d>>h&1)===1),e.set(l,v-S,b),h--,h===-1&&(d++,h=7)}if(l+=s,l<0||n<=l){l-=s,s=-s;break}}}i(IU,"setupData");function FU(e,t,n){let s=new bU;n.forEach(function(S){s.put(S.mode.bit,4),s.put(S.getLength(),LU.getCharCountIndicator(S.mode,e)),S.write(s)});let l=Z0.getSymbolTotalCodewords(e),h=sE.getTotalCodewordsCount(e,t),d=(l-h)*8;for(s.getLengthInBits()+4<=d&&s.put(0,4);s.getLengthInBits()%8!==0;)s.putBit(0);let v=(d-s.getLengthInBits())/8;for(let S=0;S=7&&NB(C,t),LB(C,c),isNaN(l)&&(l=kC.getBestMask(C,PC.bind(null,C,n))),kC.applyMask(l,C),PC(C,n,l),{modules:C,version:t,errorCorrectionLevel:n,maskPattern:l,segments:d}}o(MB,"createSymbol");AP.create=o(function(t,n){if(typeof t=="undefined"||t==="")throw new Error("No input text");let l=TC.M,d,h;return typeof n!="undefined"&&(l=TC.from(n.errorCorrectionLevel,TC.M),d=_y.from(n.version),h=kC.from(n.maskPattern),n.toSJISFunc&&Ey.setToSJISFunction(n.toSJISFunc)),MB(t,d,l,h)},"create")});var OC=Ue(Gf=>{function RP(e){if(typeof e=="number"&&(e=e.toString()),typeof e!="string")throw new Error("Color should be defined as hex string");let t=e.slice().replace("#","").split("");if(t.length<3||t.length===5||t.length>8)throw new Error("Invalid hex color: "+e);(t.length===3||t.length===4)&&(t=Array.prototype.concat.apply([],t.map(function(l){return[l,l]}))),t.length===6&&t.push("F","F");let n=parseInt(t.join(""),16);return{r:n>>24&255,g:n>>16&255,b:n>>8&255,a:n&255,hex:"#"+t.slice(0,6).join("")}}o(RP,"hex2rgba");Gf.getOptions=o(function(t){t||(t={}),t.color||(t.color={});let n=typeof t.margin=="undefined"||t.margin===null||t.margin<0?4:t.margin,l=t.width&&t.width>=21?t.width:void 0,d=t.scale||4;return{width:l,scale:l?4:d,margin:n,color:{dark:RP(t.color.dark||"#000000ff"),light:RP(t.color.light||"#ffffffff")},type:t.type,rendererOpts:t.rendererOpts||{}}},"getOptions");Gf.getScale=o(function(t,n){return n.width&&n.width>=t+n.margin*2?n.width/(t+n.margin*2):n.scale},"getScale");Gf.getImageWidth=o(function(t,n){let l=Gf.getScale(t,n);return Math.floor((t+n.margin*2)*l)},"getImageWidth");Gf.qrToImageData=o(function(t,n,l){let d=n.modules.size,h=n.modules.data,c=Gf.getScale(d,l),v=Math.floor((d+l.margin*2)*c),C=l.margin*c,k=[l.color.light,l.color.dark];for(let O=0;O=C&&j>=C&&O{var MC=OC();function AB(e,t,n){e.clearRect(0,0,t.width,t.height),t.style||(t.style={}),t.height=n,t.width=n,t.style.height=n+"px",t.style.width=n+"px"}o(AB,"clearCanvas");function DB(){try{return document.createElement("canvas")}catch(e){throw new Error("You need to specify a canvas element")}}o(DB,"getCanvasElement");Ty.render=o(function(t,n,l){let d=l,h=n;typeof d=="undefined"&&(!n||!n.getContext)&&(d=n,n=void 0),n||(h=DB()),d=MC.getOptions(d);let c=MC.getImageWidth(t.modules.size,d),v=h.getContext("2d"),C=v.createImageData(c,c);return MC.qrToImageData(C.data,t,d),AB(v,h,c),v.putImageData(C,0,0),h},"render");Ty.renderToDataURL=o(function(t,n,l){let d=l;typeof d=="undefined"&&(!n||!n.getContext)&&(d=n,n=void 0),d||(d={});let h=Ty.render(t,n,d),c=d.type||"image/png",v=d.rendererOpts||{};return h.toDataURL(c,v.quality)},"renderToDataURL")});var HP=Ue(BP=>{var RB=OC();function FP(e,t){let n=e.a/255,l=t+'="'+e.hex+'"';return n<1?l+" "+t+'-opacity="'+n.toFixed(2).slice(1)+'"':l}o(FP,"getColorAttrib");function AC(e,t,n){let l=e+t;return typeof n!="undefined"&&(l+=" "+n),l}o(AC,"svgCmd");function IB(e,t,n){let l="",d=0,h=!1,c=0;for(let v=0;v0&&C>0&&e[v-1]||(l+=h?AC("M",C+n,.5+k+n):AC("m",d,0),d=0,h=!1),C+1':"",k="',O='viewBox="0 0 '+v+" "+v+'"',j=d.width?'width="'+d.width+'" height="'+d.width+'" ':"",B=''+C+k+` -`;return typeof l=="function"&&l(null,B),B},"render")});var UP=Ue(Am=>{var FB=UL(),DC=DP(),WP=IP(),BB=HP();function RC(e,t,n,l,d){let h=[].slice.call(arguments,1),c=h.length,v=typeof h[c-1]=="function";if(!v&&!FB())throw new Error("Callback required as last argument");if(v){if(c<2)throw new Error("Too few arguments provided");c===2?(d=n,n=t,t=l=void 0):c===3&&(t.getContext&&typeof d=="undefined"?(d=l,l=void 0):(d=l,l=n,n=t,t=void 0))}else{if(c<1)throw new Error("Too few arguments provided");return c===1?(n=t,t=l=void 0):c===2&&!t.getContext&&(l=n,n=t,t=void 0),new Promise(function(C,k){try{let O=DC.create(n,l);C(e(O,t,l))}catch(O){k(O)}})}try{let C=DC.create(n,l);d(null,e(C,t,l))}catch(C){d(C)}}o(RC,"renderCanvas");Am.create=DC.create;Am.toCanvas=RC.bind(null,WP.render);Am.toDataURL=RC.bind(null,WP.renderToDataURL);Am.toString=RC.bind(null,function(e,t,n){return BB.render(e,n)})});var ib=fe(Oe()),uO=fe(iu());var Gh=fe(Oe()),NH=fe(uk());var fk=fe(Oe()),ei=fk.default.createContext(null);function _I(e){e()}o(_I,"defaultNoopBatch");var ck=_I,pk=o(function(t){return ck=t},"setBatch"),dk=o(function(){return ck},"getBatch");var hk={notify:o(function(){},"notify")};function TI(){var e=dk(),t=null,n=null;return{clear:o(function(){t=null,n=null},"clear"),notify:o(function(){e(function(){for(var d=t;d;)d.callback(),d=d.next})},"notify"),get:o(function(){for(var d=[],h=t;h;)d.push(h),h=h.next;return d},"get"),subscribe:o(function(d){var h=!0,c=n={callback:d,next:null,prev:n};return c.prev?c.prev.next=c:t=c,o(function(){!h||t===null||(h=!1,c.next?c.next.prev=c.prev:n=c.prev,c.prev?c.prev.next=c.next:t=c.next)},"unsubscribe")},"subscribe")}}o(TI,"createListenerCollection");var Tp=function(){function e(n,l){this.store=n,this.parentSub=l,this.unsubscribe=null,this.listeners=hk,this.handleChangeWrapper=this.handleChangeWrapper.bind(this)}o(e,"Subscription");var t=e.prototype;return t.addNestedSub=o(function(l){return this.trySubscribe(),this.listeners.subscribe(l)},"addNestedSub"),t.notifyNestedSubs=o(function(){this.listeners.notify()},"notifyNestedSubs"),t.handleChangeWrapper=o(function(){this.onStateChange&&this.onStateChange()},"handleChangeWrapper"),t.isSubscribed=o(function(){return Boolean(this.unsubscribe)},"isSubscribed"),t.trySubscribe=o(function(){this.unsubscribe||(this.unsubscribe=this.parentSub?this.parentSub.addNestedSub(this.handleChangeWrapper):this.store.subscribe(this.handleChangeWrapper),this.listeners=TI())},"trySubscribe"),t.tryUnsubscribe=o(function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null,this.listeners.clear(),this.listeners=hk)},"tryUnsubscribe"),e}();var Yv=fe(Oe()),Nf=typeof window!="undefined"&&typeof window.document!="undefined"&&typeof window.document.createElement!="undefined"?Yv.useLayoutEffect:Yv.useEffect;function kI(e){var t=e.store,n=e.context,l=e.children,d=(0,Gh.useMemo)(function(){var v=new Tp(t);return v.onStateChange=v.notifyNestedSubs,{store:t,subscription:v}},[t]),h=(0,Gh.useMemo)(function(){return t.getState()},[t]);Nf(function(){var v=d.subscription;return v.trySubscribe(),h!==t.getState()&&v.notifyNestedSubs(),function(){v.tryUnsubscribe(),v.onStateChange=null}},[d,h]);var c=n||ei;return Gh.default.createElement(c.Provider,{value:d},l)}o(kI,"Provider");var Wx=kI;function Po(){return Po=Object.assign||function(e){for(var t=1;t=0)&&(n[d]=e[d]);return n}o(ou,"_objectWithoutPropertiesLoose");var Yx=fe(_k()),cr=fe(Oe()),Pk=fe(Lk());var qI=[],VI=[null,null];function KI(e,t){var n=e[1];return[t.payload,n+1]}o(KI,"storeStateUpdatesReducer");function Ok(e,t,n){Nf(function(){return e.apply(void 0,t)},n)}o(Ok,"useIsomorphicLayoutEffectWithArgs");function GI(e,t,n,l,d,h,c){e.current=l,t.current=d,n.current=!1,h.current&&(h.current=null,c())}o(GI,"captureWrapperProps");function YI(e,t,n,l,d,h,c,v,C,k){if(!!e){var O=!1,j=null,B=o(function(){if(!O){var Z=t.getState(),R,A;try{R=l(Z,d.current)}catch(I){A=I,j=I}A||(j=null),R===h.current?c.current||C():(h.current=R,v.current=R,c.current=!0,k({type:"STORE_UPDATED",payload:{error:A}}))}},"checkForUpdates");n.onStateChange=B,n.trySubscribe(),B();var X=o(function(){if(O=!0,n.tryUnsubscribe(),n.onStateChange=null,j)throw j},"unsubscribeWrapper");return X}}o(YI,"subscribeUpdates");var XI=o(function(){return[null,0]},"initStateUpdates");function g0(e,t){t===void 0&&(t={});var n=t,l=n.getDisplayName,d=l===void 0?function(ne){return"ConnectAdvanced("+ne+")"}:l,h=n.methodName,c=h===void 0?"connectAdvanced":h,v=n.renderCountProp,C=v===void 0?void 0:v,k=n.shouldHandleStateChanges,O=k===void 0?!0:k,j=n.storeKey,B=j===void 0?"store":j,X=n.withRef,J=X===void 0?!1:X,Z=n.forwardRef,R=Z===void 0?!1:Z,A=n.context,I=A===void 0?ei:A,G=ou(n,["getDisplayName","methodName","renderCountProp","shouldHandleStateChanges","storeKey","withRef","forwardRef","context"]);if(!1)var K;var se=I;return o(function(pe){var me=pe.displayName||pe.name||"Component",xe=d(me),Ve=Po({},G,{getDisplayName:d,methodName:c,renderCountProp:C,shouldHandleStateChanges:O,storeKey:B,displayName:xe,wrappedComponentName:me,WrappedComponent:pe}),tt=G.pure;function _e(Xe){return e(Xe.dispatch,Ve)}o(_e,"createChildSelector");var St=tt?cr.useMemo:function(Xe){return Xe()};function We(Xe){var nr=(0,cr.useMemo)(function(){var Cr=Xe.reactReduxForwardedRef,Ui=ou(Xe,["reactReduxForwardedRef"]);return[Xe.context,Cr,Ui]},[Xe]),ct=nr[0],Hr=nr[1],Zt=nr[2],_t=(0,cr.useMemo)(function(){return ct&&ct.Consumer&&(0,Pk.isContextConsumer)(cr.default.createElement(ct.Consumer,null))?ct:se},[ct,se]),Ct=(0,cr.useContext)(_t),ut=Boolean(Xe.store)&&Boolean(Xe.store.getState)&&Boolean(Xe.store.dispatch),Lr=Boolean(Ct)&&Boolean(Ct.store),zt=ut?Xe.store:Ct.store,$t=(0,cr.useMemo)(function(){return _e(zt)},[zt]),ie=(0,cr.useMemo)(function(){if(!O)return VI;var Cr=new Tp(zt,ut?null:Ct.subscription),Ui=Cr.notifyNestedSubs.bind(Cr);return[Cr,Ui]},[zt,ut,Ct]),rt=ie[0],Pr=ie[1],Gt=(0,cr.useMemo)(function(){return ut?Ct:Po({},Ct,{subscription:rt})},[ut,Ct,rt]),Yt=(0,cr.useReducer)(KI,qI,XI),Se=Yt[0],Or=Se[0],fn=Yt[1];if(Or&&Or.error)throw Or.error;var Un=(0,cr.useRef)(),si=(0,cr.useRef)(Zt),cn=(0,cr.useRef)(),Jt=(0,cr.useRef)(!1),gr=St(function(){return cn.current&&Zt===si.current?cn.current:$t(zt.getState(),Zt)},[zt,Or,Zt]);Ok(GI,[si,Un,Jt,Zt,gr,cn,Pr]),Ok(YI,[O,zt,rt,$t,si,Un,Jt,cn,Pr,fn],[zt,rt,$t]);var pt=(0,cr.useMemo)(function(){return cr.default.createElement(pe,Po({},gr,{ref:Hr}))},[Hr,pe,gr]),Ho=(0,cr.useMemo)(function(){return O?cr.default.createElement(_t.Provider,{value:Gt},pt):pt},[_t,pt,Gt]);return Ho}o(We,"ConnectFunction");var Ke=tt?cr.default.memo(We):We;if(Ke.WrappedComponent=pe,Ke.displayName=We.displayName=xe,R){var Ge=cr.default.forwardRef(o(function(nr,ct){return cr.default.createElement(Ke,Po({},nr,{reactReduxForwardedRef:ct}))},"forwardConnectRef"));return Ge.displayName=xe,Ge.WrappedComponent=pe,(0,Yx.default)(Ge,pe)}return(0,Yx.default)(Ke,pe)},"wrapWithConnect")}o(g0,"connectAdvanced");function Mk(e,t){return e===t?e!==0||t!==0||1/e==1/t:e!==e&&t!==t}o(Mk,"is");function kp(e,t){if(Mk(e,t))return!0;if(typeof e!="object"||e===null||typeof t!="object"||t===null)return!1;var n=Object.keys(e),l=Object.keys(t);if(n.length!==l.length)return!1;for(var d=0;d=0;l--){var d=t[l](e);if(d)return d}return function(h,c){throw new Error("Invalid value of type "+typeof e+" for "+n+" argument when connecting component "+c.wrappedComponentName+".")}}o(Zx,"match");function uF(e,t){return e===t}o(uF,"strictEqual");function fF(e){var t=e===void 0?{}:e,n=t.connectHOC,l=n===void 0?g0:n,d=t.mapStateToPropsFactories,h=d===void 0?Rk:d,c=t.mapDispatchToPropsFactories,v=c===void 0?Dk:c,C=t.mergePropsFactories,k=C===void 0?Ik:C,O=t.selectorFactory,j=O===void 0?Qx:O;return o(function(X,J,Z,R){R===void 0&&(R={});var A=R,I=A.pure,G=I===void 0?!0:I,K=A.areStatesEqual,se=K===void 0?uF:K,ne=A.areOwnPropsEqual,pe=ne===void 0?kp:ne,me=A.areStatePropsEqual,xe=me===void 0?kp:me,Ve=A.areMergedPropsEqual,tt=Ve===void 0?kp:Ve,_e=ou(A,["pure","areStatesEqual","areOwnPropsEqual","areStatePropsEqual","areMergedPropsEqual"]),St=Zx(X,h,"mapStateToProps"),We=Zx(J,v,"mapDispatchToProps"),Ke=Zx(Z,k,"mergeProps");return l(j,Po({methodName:"connect",getDisplayName:o(function(Xe){return"Connect("+Xe+")"},"getDisplayName"),shouldHandleStateChanges:Boolean(X),initMapStateToProps:St,initMapDispatchToProps:We,initMergeProps:Ke,pure:G,areStatesEqual:se,areOwnPropsEqual:pe,areStatePropsEqual:xe,areMergedPropsEqual:tt},_e))},"connect")}o(fF,"createConnect");var Hi=fF();var Bk=fe(Oe());var Fk=fe(Oe());function y0(){var e=(0,Fk.useContext)(ei);return e}o(y0,"useReduxContext");function w0(e){e===void 0&&(e=ei);var t=e===ei?y0:function(){return(0,Bk.useContext)(e)};return o(function(){var l=t(),d=l.store;return d},"useStore")}o(w0,"createStoreHook");var Jx=w0();function Hk(e){e===void 0&&(e=ei);var t=e===ei?Jx:w0(e);return o(function(){var l=t();return l.dispatch},"useDispatch")}o(Hk,"createDispatchHook");var Gs=Hk();var ro=fe(Oe());var cF=o(function(t,n){return t===n},"refEquality");function pF(e,t,n,l){var d=(0,ro.useReducer)(function(J){return J+1},0),h=d[1],c=(0,ro.useMemo)(function(){return new Tp(n,l)},[n,l]),v=(0,ro.useRef)(),C=(0,ro.useRef)(),k=(0,ro.useRef)(),O=(0,ro.useRef)(),j=n.getState(),B;try{if(e!==C.current||j!==k.current||v.current){var X=e(j);O.current===void 0||!t(X,O.current)?B=X:B=O.current}else B=O.current}catch(J){throw v.current&&(J.message+=` +`);let d=FU(t,n,l),v=Z0.getSymbolSize(t),S=new TU(v);return MU(S,t),OU(S),RU(S,t),iE(S,n,0),t>=7&&DU(S,t),IU(S,d),isNaN(s)&&(s=oE.getBestMask(S,iE.bind(null,S,n))),oE.applyMask(s,S),iE(S,n,s),{modules:S,version:t,errorCorrectionLevel:n,maskPattern:s,segments:l}}i(HU,"createSymbol");QM.create=i(function(t,n){if(typeof t>"u"||t==="")throw new Error("No input text");let s=rE.M,l,h;return typeof n<"u"&&(s=rE.from(n.errorCorrectionLevel,rE.M),l=J0.from(n.version),h=oE.from(n.maskPattern),n.toSJISFunc&&Z0.setToSJISFunction(n.toSJISFunc)),HU(t,l,s,h)},"create")});var aE=rt(zf=>{function ZM(e){if(typeof e=="number"&&(e=e.toString()),typeof e!="string")throw new Error("Color should be defined as hex string");let t=e.slice().replace("#","").split("");if(t.length<3||t.length===5||t.length>8)throw new Error("Invalid hex color: "+e);(t.length===3||t.length===4)&&(t=Array.prototype.concat.apply([],t.map(function(s){return[s,s]}))),t.length===6&&t.push("F","F");let n=parseInt(t.join(""),16);return{r:n>>24&255,g:n>>16&255,b:n>>8&255,a:n&255,hex:"#"+t.slice(0,6).join("")}}i(ZM,"hex2rgba");zf.getOptions=i(function(t){t||(t={}),t.color||(t.color={});let n=typeof t.margin>"u"||t.margin===null||t.margin<0?4:t.margin,s=t.width&&t.width>=21?t.width:void 0,l=t.scale||4;return{width:s,scale:s?4:l,margin:n,color:{dark:ZM(t.color.dark||"#000000ff"),light:ZM(t.color.light||"#ffffffff")},type:t.type,rendererOpts:t.rendererOpts||{}}},"getOptions");zf.getScale=i(function(t,n){return n.width&&n.width>=t+n.margin*2?n.width/(t+n.margin*2):n.scale},"getScale");zf.getImageWidth=i(function(t,n){let s=zf.getScale(t,n);return Math.floor((t+n.margin*2)*s)},"getImageWidth");zf.qrToImageData=i(function(t,n,s){let l=n.modules.size,h=n.modules.data,d=zf.getScale(l,s),v=Math.floor((l+s.margin*2)*d),S=s.margin*d,b=[s.color.light,s.color.dark];for(let k=0;k=S&&R>=S&&k{var lE=aE();function zU(e,t,n){e.clearRect(0,0,t.width,t.height),t.style||(t.style={}),t.height=n,t.width=n,t.style.height=n+"px",t.style.width=n+"px"}i(zU,"clearCanvas");function UU(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}i(UU,"getCanvasElement");ew.render=i(function(t,n,s){let l=s,h=n;typeof l>"u"&&(!n||!n.getContext)&&(l=n,n=void 0),n||(h=UU()),l=lE.getOptions(l);let d=lE.getImageWidth(t.modules.size,l),v=h.getContext("2d"),S=v.createImageData(d,d);return lE.qrToImageData(S.data,t,l),zU(v,h,d),v.putImageData(S,0,0),h},"render");ew.renderToDataURL=i(function(t,n,s){let l=s;typeof l>"u"&&(!n||!n.getContext)&&(l=n,n=void 0),l||(l={});let h=ew.render(t,n,l),d=l.type||"image/png",v=l.rendererOpts||{};return h.toDataURL(d,v.quality)},"renderToDataURL")});var nO=rt(rO=>{var WU=aE();function tO(e,t){let n=e.a/255,s=t+'="'+e.hex+'"';return n<1?s+" "+t+'-opacity="'+n.toFixed(2).slice(1)+'"':s}i(tO,"getColorAttrib");function uE(e,t,n){let s=e+t;return typeof n<"u"&&(s+=" "+n),s}i(uE,"svgCmd");function $U(e,t,n){let s="",l=0,h=!1,d=0;for(let v=0;v0&&S>0&&e[v-1]||(s+=h?uE("M",S+n,.5+b+n):uE("m",l,0),l=0,h=!1),S+1':"",b="',k='viewBox="0 0 '+v+" "+v+'"',I=''+S+b+` +`;return typeof s=="function"&&s(null,I),I},"render")});var oO=rt(lg=>{var VU=oM(),cE=JM(),iO=eO(),qU=nO();function fE(e,t,n,s,l){let h=[].slice.call(arguments,1),d=h.length,v=typeof h[d-1]=="function";if(!v&&!VU())throw new Error("Callback required as last argument");if(v){if(d<2)throw new Error("Too few arguments provided");d===2?(l=n,n=t,t=s=void 0):d===3&&(t.getContext&&typeof l>"u"?(l=s,s=void 0):(l=s,s=n,n=t,t=void 0))}else{if(d<1)throw new Error("Too few arguments provided");return d===1?(n=t,t=s=void 0):d===2&&!t.getContext&&(s=n,n=t,t=void 0),new Promise(function(S,b){try{let k=cE.create(n,s);S(e(k,t,s))}catch(k){b(k)}})}try{let S=cE.create(n,s);l(null,e(S,t,s))}catch(S){l(S)}}i(fE,"renderCanvas");lg.create=cE.create;lg.toCanvas=fE.bind(null,iO.render);lg.toDataURL=fE.bind(null,iO.renderToDataURL);lg.toString=fE.bind(null,function(e,t,n){return qU.render(e,n)})});var gO=rt((Cee,mO)=>{"use strict";var dW="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";mO.exports=dW});var SO=rt((_ee,wO)=>{"use strict";var pW=gO();function vO(){}i(vO,"emptyFunction");function yO(){}i(yO,"emptyFunctionWithReset");yO.resetWarningCache=vO;wO.exports=function(){function e(s,l,h,d,v,S){if(S!==pW){var b=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw b.name="Invariant Violation",b}}i(e,"shim"),e.isRequired=e;function t(){return e}i(t,"getShim");var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:yO,resetWarningCache:vO};return n.PropTypes=n,n}});var CO=rt((kee,xO)=>{xO.exports=SO()();var bee,Tee});var $E=pe(Te()),LO=pe(eA());var pA=pe(Te(),1),hA=pe(iA(),1),Oy=pe(Te(),1);var Tt="default"in Oy?Oy.default:Oy,oA=Symbol.for("react-redux-context"),sA=typeof globalThis<"u"?globalThis:{};function s4(){if(!Tt.createContext)return{};let e=sA[oA]??(sA[oA]=new Map),t=e.get(Tt.createContext);return t||(t=Tt.createContext(null),e.set(Tt.createContext,t)),t}i(s4,"getContext");var gl=s4(),mA=i(()=>{throw new Error("uSES not initialized!")},"notInitialized");function Cx(e=gl){return i(function(){return Tt.useContext(e)},"useReduxContext2")}i(Cx,"createReduxContextHook");var gA=Cx(),vA=mA,a4=i(e=>{vA=e},"initializeUseSelector"),l4=i((e,t)=>e===t,"refEquality");function u4(e=gl){let t=e===gl?gA:Cx(e),n=i((s,l={})=>{let{equalityFn:h=l4,devModeChecks:d={}}=typeof l=="function"?{equalityFn:l}:l,{store:v,subscription:S,getServerState:b,stabilityCheck:k,identityFunctionCheck:R}=t(),I=Tt.useRef(!0),z=Tt.useCallback({[s.name](Q){let ne=s(Q);if(0){if((L==="always"||L==="once"&&I.current)&&!h(ne,B))try{}catch(re){}if((D==="always"||D==="once"&&I.current)&&ne===Q)try{}catch(j){}}return ne}}[s.name],[s,k,d.stabilityCheck]),q=vA(S.addNestedSub,v.getState,b||v.getState,z,h);return Tt.useDebugValue(q),q},"useSelector2");return Object.assign(n,{withTypes:i(()=>n,"withTypes")}),n}i(u4,"createSelectorHook");var yA=u4(),c4=Symbol.for("react.element"),f4=Symbol.for("react.portal"),d4=Symbol.for("react.fragment"),p4=Symbol.for("react.strict_mode"),h4=Symbol.for("react.profiler"),m4=Symbol.for("react.provider"),g4=Symbol.for("react.context"),v4=Symbol.for("react.server_context"),wA=Symbol.for("react.forward_ref"),y4=Symbol.for("react.suspense"),w4=Symbol.for("react.suspense_list"),_x=Symbol.for("react.memo"),S4=Symbol.for("react.lazy"),VW=Symbol.for("react.offscreen"),qW=Symbol.for("react.client.reference"),x4=wA,C4=_x;function _4(e){if(typeof e=="object"&&e!==null){let t=e.$$typeof;switch(t){case c4:{let n=e.type;switch(n){case d4:case h4:case p4:case y4:case w4:return n;default:{let s=n&&n.$$typeof;switch(s){case v4:case g4:case wA:case S4:case _x:case m4:return s;default:return t}}}}case f4:return t}}}i(_4,"typeOf");function E4(e){return _4(e)===_x}i(E4,"isMemo");function b4(e,t,n,s,{areStatesEqual:l,areOwnPropsEqual:h,areStatePropsEqual:d}){let v=!1,S,b,k,R,I;function z(L,B){return S=L,b=B,k=e(S,b),R=t(s,b),I=n(k,R,b),v=!0,I}i(z,"handleFirstCall");function q(){return k=e(S,b),t.dependsOnOwnProps&&(R=t(s,b)),I=n(k,R,b),I}i(q,"handleNewPropsAndNewState");function Q(){return e.dependsOnOwnProps&&(k=e(S,b)),t.dependsOnOwnProps&&(R=t(s,b)),I=n(k,R,b),I}i(Q,"handleNewProps");function ne(){let L=e(S,b),B=!d(L,k);return k=L,B&&(I=n(k,R,b)),I}i(ne,"handleNewState");function D(L,B){let j=!h(B,b),re=!l(L,S,B,b);return S=L,b=B,j&&re?q():j?Q():re?ne():I}return i(D,"handleSubsequentCalls"),i(function(B,j){return v?D(B,j):z(B,j)},"pureFinalPropsSelector")}i(b4,"pureFinalPropsSelectorFactory");function T4(e,{initMapStateToProps:t,initMapDispatchToProps:n,initMergeProps:s,...l}){let h=t(e,l),d=n(e,l),v=s(e,l);return b4(h,d,v,e,l)}i(T4,"finalPropsSelectorFactory");function k4(e,t){let n={};for(let s in e){let l=e[s];typeof l=="function"&&(n[s]=(...h)=>t(l(...h)))}return n}i(k4,"bindActionCreators");function Sx(e){return i(function(n){let s=e(n);function l(){return s}return i(l,"constantSelector"),l.dependsOnOwnProps=!1,l},"initConstantSelector")}i(Sx,"wrapMapToPropsConstant");function aA(e){return e.dependsOnOwnProps?!!e.dependsOnOwnProps:e.length!==1}i(aA,"getDependsOnOwnProps");function SA(e,t){return i(function(s,{displayName:l}){let h=i(function(v,S){return h.dependsOnOwnProps?h.mapToProps(v,S):h.mapToProps(v,void 0)},"mapToPropsProxy");return h.dependsOnOwnProps=!0,h.mapToProps=i(function(v,S){h.mapToProps=e,h.dependsOnOwnProps=aA(e);let b=h(v,S);return typeof b=="function"&&(h.mapToProps=b,h.dependsOnOwnProps=aA(b),b=h(v,S)),b},"detectFactoryAndVerify"),h},"initProxySelector")}i(SA,"wrapMapToPropsFunc");function Ex(e,t){return(n,s)=>{throw new Error(`Invalid value of type ${typeof e} for ${t} argument when connecting component ${s.wrappedComponentName}.`)}}i(Ex,"createInvalidArgFactory");function N4(e){return e&&typeof e=="object"?Sx(t=>k4(e,t)):e?typeof e=="function"?SA(e,"mapDispatchToProps"):Ex(e,"mapDispatchToProps"):Sx(t=>({dispatch:t}))}i(N4,"mapDispatchToPropsFactory");function A4(e){return e?typeof e=="function"?SA(e,"mapStateToProps"):Ex(e,"mapStateToProps"):Sx(()=>({}))}i(A4,"mapStateToPropsFactory");function P4(e,t,n){return{...n,...e,...t}}i(P4,"defaultMergeProps");function L4(e){return i(function(n,{displayName:s,areMergedPropsEqual:l}){let h=!1,d;return i(function(S,b,k){let R=e(S,b,k);return h?l(R,d)||(d=R):(h=!0,d=R),d},"mergePropsProxy")},"initMergePropsProxy")}i(L4,"wrapMergePropsFunc");function M4(e){return e?typeof e=="function"?L4(e):Ex(e,"mergeProps"):()=>P4}i(M4,"mergePropsFactory");function O4(e){e()}i(O4,"defaultNoopBatch");function R4(){let e=null,t=null;return{clear(){e=null,t=null},notify(){O4(()=>{let n=e;for(;n;)n.callback(),n=n.next})},get(){let n=[],s=e;for(;s;)n.push(s),s=s.next;return n},subscribe(n){let s=!0,l=t={callback:n,next:null,prev:t};return l.prev?l.prev.next=l:e=l,i(function(){!s||e===null||(s=!1,l.next?l.next.prev=l.prev:t=l.prev,l.prev?l.prev.next=l.next:e=l.next)},"unsubscribe")}}}i(R4,"createListenerCollection");var lA={notify(){},get:i(()=>[],"get")};function xA(e,t){let n,s=lA,l=0,h=!1;function d(Q){k();let ne=s.subscribe(Q),D=!1;return()=>{D||(D=!0,ne(),R())}}i(d,"addNestedSub");function v(){s.notify()}i(v,"notifyNestedSubs");function S(){q.onStateChange&&q.onStateChange()}i(S,"handleChangeWrapper");function b(){return h}i(b,"isSubscribed");function k(){l++,n||(n=t?t.addNestedSub(S):e.subscribe(S),s=R4())}i(k,"trySubscribe");function R(){l--,n&&l===0&&(n(),n=void 0,s.clear(),s=lA)}i(R,"tryUnsubscribe");function I(){h||(h=!0,k())}i(I,"trySubscribeSelf");function z(){h&&(h=!1,R())}i(z,"tryUnsubscribeSelf");let q={addNestedSub:d,notifyNestedSubs:v,handleChangeWrapper:S,isSubscribed:b,trySubscribe:I,tryUnsubscribe:z,getListeners:i(()=>s,"getListeners")};return q}i(xA,"createSubscription");var D4=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",I4=typeof navigator<"u"&&navigator.product==="ReactNative",Ry=D4||I4?Tt.useLayoutEffect:Tt.useEffect;function uA(e,t){return e===t?e!==0||t!==0||1/e===1/t:e!==e&&t!==t}i(uA,"is");function Mo(e,t){if(uA(e,t))return!0;if(typeof e!="object"||e===null||typeof t!="object"||t===null)return!1;let n=Object.keys(e),s=Object.keys(t);if(n.length!==s.length)return!1;for(let l=0;l{_A=e},"initializeConnect"),j4=[null,null];function K4(e,t,n){Ry(()=>e(...t),n)}i(K4,"useIsomorphicLayoutEffectWithArgs");function G4(e,t,n,s,l,h){e.current=s,n.current=!1,l.current&&(l.current=null,h())}i(G4,"captureWrapperProps");function Y4(e,t,n,s,l,h,d,v,S,b,k){if(!e)return()=>{};let R=!1,I=null,z=i(()=>{if(R||!v.current)return;let Q=t.getState(),ne,D;try{ne=s(Q,l.current)}catch(L){D=L,I=L}D||(I=null),ne===h.current?d.current||b():(h.current=ne,S.current=ne,d.current=!0,k())},"checkForUpdates");return n.onStateChange=z,n.trySubscribe(),z(),i(()=>{if(R=!0,n.tryUnsubscribe(),n.onStateChange=null,I)throw I},"unsubscribeWrapper")}i(Y4,"subscribeUpdates");function X4(e,t){return e===t}i(X4,"strictEqual");function Q4(e,t,n,{pure:s,areStatesEqual:l=X4,areOwnPropsEqual:h=Mo,areStatePropsEqual:d=Mo,areMergedPropsEqual:v=Mo,forwardRef:S=!1,context:b=gl}={}){let k=b,R=A4(e),I=N4(t),z=M4(n),q=!!e;return i(ne=>{let D=ne.displayName||ne.name||"Component",L=`Connect(${D})`,B={shouldHandleStateChanges:q,displayName:L,wrappedComponentName:D,WrappedComponent:ne,initMapStateToProps:R,initMapDispatchToProps:I,initMergeProps:z,areStatesEqual:l,areStatePropsEqual:d,areOwnPropsEqual:h,areMergedPropsEqual:v};function j(oe){let[he,Re,Ee]=Tt.useMemo(()=>{let{reactReduxForwardedRef:st,...Fe}=oe;return[oe.context,st,Fe]},[oe]),Ye=Tt.useMemo(()=>{let st=k;return he?.Consumer,st},[he,k]),tt=Tt.useContext(Ye),xe=!!oe.store&&!!oe.store.getState&&!!oe.store.dispatch,Xe=!!tt&&!!tt.store,je=xe?oe.store:tt.store,Qe=Xe?tt.getServerState:je.getState,ot=Tt.useMemo(()=>T4(je.dispatch,B),[je]),[It,At]=Tt.useMemo(()=>{if(!q)return j4;let st=xA(je,xe?void 0:tt.subscription),Fe=st.notifyNestedSubs.bind(st);return[st,Fe]},[je,xe,tt]),cn=Tt.useMemo(()=>xe?tt:{...tt,subscription:It},[xe,tt,It]),fn=Tt.useRef(void 0),gr=Tt.useRef(Ee),Wt=Tt.useRef(void 0),vr=Tt.useRef(!1),yr=Tt.useRef(!1),Gt=Tt.useRef(void 0);Ry(()=>(yr.current=!0,()=>{yr.current=!1}),[]);let Ft=Tt.useMemo(()=>i(()=>Wt.current&&Ee===gr.current?Wt.current:ot(je.getState(),Ee),"selector"),[je,Ee]),se=Tt.useMemo(()=>i(Fe=>It?Y4(q,je,It,ot,gr,fn,vr,yr,Wt,At,Fe):()=>{},"subscribe"),[It]);K4(G4,[gr,fn,vr,Ee,Wt,At]);let Ue;try{Ue=_A(se,Ft,Qe?()=>ot(Qe(),Ee):Ft)}catch(st){throw Gt.current&&(st.message+=` The error may be correlated with this previous error: -`+v.current.stack+` +${Gt.current.stack} -`),J}return Nf(function(){C.current=e,k.current=j,O.current=B,v.current=void 0}),Nf(function(){function J(){try{var Z=n.getState(),R=C.current(Z);if(t(R,O.current))return;O.current=R,k.current=Z}catch(A){v.current=A}h()}return o(J,"checkForUpdates"),c.onStateChange=J,c.trySubscribe(),J(),function(){return c.tryUnsubscribe()}},[n,c]),B}o(pF,"useSelectorWithStoreAndSubscription");function Wk(e){e===void 0&&(e=ei);var t=e===ei?y0:function(){return(0,ro.useContext)(e)};return o(function(l,d){d===void 0&&(d=cF);var h=t(),c=h.store,v=h.subscription,C=pF(l,d,c,v);return(0,ro.useDebugValue)(C),C},"useSelector")}o(Wk,"createSelectorHook");var eS=Wk();var tS=fe(iu());pk(tS.unstable_batchedUpdates);var Wn=fe(Oe());var Uk="UI_FLOWVIEW_SET_TAB",zk="SET_CONTENT_VIEW_FOR",dF={tab:"request",contentViewFor:{}};function rS(e=dF,t){switch(t.type){case zk:return Pt(ke({},e),{contentViewFor:Pt(ke({},e.contentViewFor),{[t.messageId]:t.contentView})});case Uk:return Pt(ke({},e),{tab:t.tab?t.tab:"request"});default:return e}}o(rS,"reducer");function Lf(e){return{type:Uk,tab:e}}o(Lf,"selectTab");function x0(e,t){return{type:zk,messageId:e,contentView:t}}o(x0,"setContentViewFor");var $k=fe(Qh()),hF=fe(Oe());window._=$k.default;window.React=hF;var S0=o(function(e){if(e===0)return"0";for(var t=["b","kb","mb","gb","tb"],n=0;ne);n++);var l;return e%Math.pow(1024,n)==0?l=0:l=1,(e/Math.pow(1024,n)).toFixed(l)+t[n]},"formatSize"),C0=o(function(e){for(var t=e,n=["ms","s","min","h"],l=[1e3,60,60],d=0;Math.abs(t)>=l[d]&&dkt(e,ke({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)},n));kt.post=(e,t,n={})=>kt(e,ke({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)},n));function Pf(e,...t){return Ia(this,null,function*(){return yield(yield kt(`/commands/${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({arguments:t})})).json()})}o(Pf,"runCommand");var Jh={};Wb(Jh,{ADD:()=>uS,RECEIVE:()=>pS,REMOVE:()=>cS,SET_FILTER:()=>lS,SET_SORT:()=>aS,UPDATE:()=>fS,add:()=>vF,defaultState:()=>b0,receive:()=>xF,reduce:()=>Lp,remove:()=>wF,setFilter:()=>dS,setSort:()=>qk,update:()=>yF});var sS=fe(jk()),lS="LIST_SET_FILTER",aS="LIST_SET_SORT",uS="LIST_ADD",fS="LIST_UPDATE",cS="LIST_REMOVE",pS="LIST_RECEIVE",b0={byId:{},list:[],listIndex:{},view:[],viewIndex:{}};function Lp(e=b0,t){let{byId:n,list:l,listIndex:d,view:h,viewIndex:c}=e;switch(t.type){case lS:h=(0,sS.default)(l.filter(t.filter),t.sort),c={},h.forEach((k,O)=>{c[k.id]=O});break;case aS:h=(0,sS.default)([...h],t.sort),c={},h.forEach((k,O)=>{c[k.id]=O});break;case uS:if(t.item.id in n)break;n=Pt(ke({},n),{[t.item.id]:t.item}),d=Pt(ke({},d),{[t.item.id]:l.length}),l=[...l,t.item],t.filter(t.item)&&({view:h,viewIndex:c}=Vk(e,t.item,t.sort));break;case fS:n=Pt(ke({},n),{[t.item.id]:t.item}),l=[...l],l[d[t.item.id]]=t.item;let v=t.item.id in c,C=t.filter(t.item);C&&!v?{view:h,viewIndex:c}=Vk(e,t.item,t.sort):!C&&v?{data:h,dataIndex:c}=hS(h,c,t.item.id):C&&v&&({view:h,viewIndex:c}=SF(e,t.item,t.sort));break;case cS:if(!(t.id in n))break;n=ke({},n),delete n[t.id],{data:l,dataIndex:d}=hS(l,d,t.id),t.id in c&&({data:h,dataIndex:c}=hS(h,c,t.id));break;case pS:l=t.list,d={},n={},l.forEach((k,O)=>{n[k.id]=k,d[k.id]=O}),h=l.filter(t.filter).sort(t.sort),c={},h.forEach((k,O)=>{c[k.id]=O});break}return{byId:n,list:l,listIndex:d,view:h,viewIndex:c}}o(Lp,"reduce");function dS(e=E0,t=Zh){return{type:lS,filter:e,sort:t}}o(dS,"setFilter");function qk(e=Zh){return{type:aS,sort:e}}o(qk,"setSort");function vF(e,t=E0,n=Zh){return{type:uS,item:e,filter:t,sort:n}}o(vF,"add");function yF(e,t=E0,n=Zh){return{type:fS,item:e,filter:t,sort:n}}o(yF,"update");function wF(e){return{type:cS,id:e}}o(wF,"remove");function xF(e,t=E0,n=Zh){return{type:pS,list:e,filter:t,sort:n}}o(xF,"receive");function Vk(e,t,n){let l=CF(e.view,t,n),d=[...e.view],h=ke({},e.viewIndex);d.splice(l,0,t);for(let c=d.length-1;c>=l;c--)h[d[c].id]=c;return{view:d,viewIndex:h}}o(Vk,"sortedInsert");function hS(e,t,n){let l=t[n],d=[...e],h=ke({},t);delete h[n],d.splice(l,1);for(let c=d.length-1;c>=l;c--)h[d[c].id]=c;return{data:d,dataIndex:h}}o(hS,"removeData");function SF(e,t,n){let l=[...e.view],d=ke({},e.viewIndex),h=d[t.id];for(l[h]=t;h+10;)l[h]=l[h+1],l[h+1]=t,d[t.id]=h+1,d[l[h].id]=h,++h;for(;h>0&&n(l[h],l[h-1])<0;)l[h]=l[h-1],l[h-1]=t,d[t.id]=h-1,d[l[h].id]=h,--h;return{view:l,viewIndex:d}}o(SF,"sortedUpdate");function CF(e,t,n){let l=0,d=e.length;for(;l>>1;n(t,e[h])>=0?l=h+1:d=h}return l}o(CF,"sortedIndex");function E0(){return!0}o(E0,"defaultFilter");function Zh(e,t){return 0}o(Zh,"defaultSort");var Kk={http:80,https:443},Kr=class{static getContentType(t){var n=Kr.get_first_header(t,/^Content-Type$/i);if(n)return n.split(";")[0].trim()}static get_first_header(t,n){let l=t;l._headerLookups||Object.defineProperty(l,"_headerLookups",{value:{},configurable:!1,enumerable:!1,writable:!1});let d=n.toString();if(!(d in l._headerLookups)){let h;for(let c=0;c{var t,n;switch(e.type){case"http":let l=e.request.contentLength||0;return e.response&&(l+=e.response.contentLength||0),e.websocket&&(l+=e.websocket.messages_meta.contentLength||0),l;case"tcp":case"udp":return e.messages_meta.contentLength||0;case"dns":return(n=(t=e.response)==null?void 0:t.size)!=null?n:0}},"getTotalSize"),_0=o(e=>e.type==="http"&&!e.websocket,"canReplay");var Of=function(){"use strict";function e(l,d){function h(){this.constructor=l}o(h,"ctor"),h.prototype=d.prototype,l.prototype=new h}o(e,"peg$subclass");function t(l,d,h,c){this.message=l,this.expected=d,this.found=h,this.location=c,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,t)}o(t,"peg$SyntaxError"),e(t,Error);function n(l){var d=arguments.length>1?arguments[1]:{},h=this,c={},v={start:Ou},C=Ou,k={type:"other",description:"filter expression"},O=o(function(w){return w},"peg$c1"),j={type:"other",description:"whitespace"},B=/^[ \t\n\r]/,X={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},J={type:"other",description:"control character"},Z=/^[|&!()~"]/,R={type:"class",value:'[|&!()~"]',description:'[|&!()~"]'},A={type:"other",description:"optional whitespace"},I="|",G={type:"literal",value:"|",description:'"|"'},K=o(function(w,T){return Au(w,T)},"peg$c11"),se="&",ne={type:"literal",value:"&",description:'"&"'},pe=o(function(w,T){return hd(w,T)},"peg$c14"),me="!",xe={type:"literal",value:"!",description:'"!"'},Ve=o(function(w){return Vo(w)},"peg$c17"),tt="(",_e={type:"literal",value:"(",description:'"("'},St=")",We={type:"literal",value:")",description:'")"'},Ke=o(function(w){return yr(w)},"peg$c22"),Ge="~all",Xe={type:"literal",value:"~all",description:'"~all"'},nr=o(function(){return fc},"peg$c25"),ct="~a",Hr={type:"literal",value:"~a",description:'"~a"'},Zt=o(function(){return Ko},"peg$c28"),_t="~b",Ct={type:"literal",value:"~b",description:'"~b"'},ut=o(function(w){return na(w)},"peg$c31"),Lr="~bq",zt={type:"literal",value:"~bq",description:'"~bq"'},$t=o(function(w){return Go(w)},"peg$c34"),ie="~bs",rt={type:"literal",value:"~bs",description:'"~bs"'},Pr=o(function(w){return md(w)},"peg$c37"),Gt="~c",Yt={type:"literal",value:"~c",description:'"~c"'},Se=o(function(w){return ia(w)},"peg$c40"),Or="~comment",fn={type:"literal",value:"~comment",description:'"~comment"'},Un=o(function(w){return Ru(w)},"peg$c43"),si="~d",cn={type:"literal",value:"~d",description:'"~d"'},Jt=o(function(w){return Iu(w)},"peg$c46"),gr="~dns",pt={type:"literal",value:"~dns",description:'"~dns"'},Ho=o(function(){return oa},"peg$c49"),Cr="~dst",Ui={type:"literal",value:"~dst",description:'"~dst"'},pn=o(function(w){return Fu(w)},"peg$c52"),zn="~e",Si={type:"literal",value:"~e",description:'"~e"'},Ci=o(function(){return Bu},"peg$c55"),$n="~h",Mn={type:"literal",value:"~h",description:'"~h"'},Js=o(function(w){return Hu(w)},"peg$c58"),H="~hq",ee={type:"literal",value:"~hq",description:'"~hq"'},he=o(function(w){return Yo(w)},"peg$c61"),Te="~hs",ir={type:"literal",value:"~hs",description:'"~hs"'},Ul=o(function(w){return ji(w)},"peg$c64"),Ft="~http",Wr={type:"literal",value:"~http",description:'"~http"'},or=o(function(){return Ss},"peg$c67"),li="~marked",ds={type:"literal",value:"~marked",description:'"~marked"'},lo=o(function(){return zr},"peg$c70"),bi="~marker",el={type:"literal",value:"~marker",description:'"~marker"'},hs=o(function(w){return sa(w)},"peg$c73"),dn="~m",id={type:"literal",value:"~m",description:'"~m"'},tl=o(function(w){return mn(w)},"peg$c76"),Qf="~q",rl={type:"literal",value:"~q",description:'"~q"'},od=o(function(){return qi},"peg$c79"),Zf="~replayq",wu={type:"literal",value:"~replayq",description:'"~replayq"'},sd=o(function(){return al},"peg$c82"),zl="~replays",ms={type:"literal",value:"~replays",description:'"~replays"'},ld=o(function(){return cc},"peg$c85"),Jf="~replay",nl={type:"literal",value:"~replay",description:'"~replay"'},xu=o(function(){return Wu},"peg$c88"),Wo="~src",ad={type:"literal",value:"~src",description:'"~src"'},Uo=o(function(w){return gd(w)},"peg$c91"),$l="~s",ec={type:"literal",value:"~s",description:'"~s"'},jt=o(function(){return Uu},"peg$c94"),Me="~tcp",Ei={type:"literal",value:"~tcp",description:'"~tcp"'},Su=o(function(){return la},"peg$c97"),ai="~udp",vt={type:"literal",value:"~udp",description:'"~udp"'},ao=o(function(){return qn},"peg$c100"),zo="~tq",jl={type:"literal",value:"~tq",description:'"~tq"'},ue=o(function(w){return Ti(w)},"peg$c103"),ze="~ts",Cu={type:"literal",value:"~ts",description:'"~ts"'},bu=o(function(w){return pc(w)},"peg$c106"),gs="~t",il={type:"literal",value:"~t",description:'"~t"'},Eu=o(function(w){return aa(w)},"peg$c109"),He="~u",ud={type:"literal",value:"~u",description:'"~u"'},ql=o(function(w){return dc(w)},"peg$c112"),uo="~websocket",ui={type:"literal",value:"~websocket",description:'"~websocket"'},tc=o(function(){return Vi},"peg$c115"),_u={type:"other",description:"integer"},$o=/^['"]/,vs={type:"class",value:`['"]`,description:`['"]`},Tu=/^[0-9]/,ol={type:"class",value:"[0-9]",description:"[0-9]"},Vl=o(function(w){return parseInt(w.join(""),10)},"peg$c121"),Kl={type:"other",description:"string"},fo='"',Gl={type:"literal",value:'"',description:'"\\""'},Yl=o(function(w){return w.join("")},"peg$c125"),rc="'",Xl={type:"literal",value:"'",description:`"'"`},_i=/^["\\]/,nc={type:"class",value:'["\\\\]',description:'["\\\\]'},Ql={type:"any",description:"any character"},co=o(function(w){return w},"peg$c131"),ys="\\",ic={type:"literal",value:"\\",description:'"\\\\"'},oc=/^['\\]/,fd={type:"class",value:"['\\\\]",description:"['\\\\]"},cd=/^['"\\]/,ku={type:"class",value:`['"\\\\]`,description:`['"\\\\]`},sc="n",Nu={type:"literal",value:"n",description:'"n"'},lc=o(function(){return` -`},"peg$c140"),ac="r",Zl={type:"literal",value:"r",description:'"r"'},Jl=o(function(){return"\r"},"peg$c143"),Lu="t",Ot={type:"literal",value:"t",description:'"t"'},Nt=o(function(){return" "},"peg$c146"),P=0,Re=0,sl=[{line:1,column:1,seenCR:!1}],vr=0,Pu=[],ye=0,jo;if("startRule"in d){if(!(d.startRule in v))throw new Error(`Can't start parsing from rule "`+d.startRule+'".');C=v[d.startRule]}function pd(){return l.substring(Re,P)}o(pd,"text");function qt(){return zi(Re,P)}o(qt,"location");function ea(w){throw ta(null,[{type:"other",description:w}],l.substring(Re,P),zi(Re,P))}o(ea,"expected");function hn(w){throw ta(w,null,l.substring(Re,P),zi(Re,P))}o(hn,"error");function ws(w){var T=sl[w],W,U;if(T)return T;for(W=w-1;!sl[W];)W--;for(T=sl[W],T={line:T.line,column:T.column,seenCR:T.seenCR};Wvr&&(vr=P,Pu=[]),Pu.push(w))}o(Ce,"peg$fail");function ta(w,T,W,U){function wr(gn){var ci=1;for(gn.sort(function(ul,ki){return ul.descriptionki.description?1:0});ci1?ki.slice(0,-1).join(", ")+" or "+ki[gn.length-1]:ki[0],zu=ci?'"'+ul(ci)+'"':"end of input","Expected "+Vn+" but "+zu+" found."}return o(Kt,"buildMessage"),T!==null&&wr(T),new t(w!==null?w:Kt(T,W),T,W,U)}o(ta,"peg$buildException");function Ou(){var w,T,W,U;return ye++,w=P,T=fi(),T!==c?(W=ll(),W!==c?(U=fi(),U!==c?(Re=w,T=O(W),w=T):(P=w,w=c)):(P=w,w=c)):(P=w,w=c),ye--,w===c&&(T=c,ye===0&&Ce(k)),w}o(Ou,"peg$parsestart");function nt(){var w,T;return ye++,B.test(l.charAt(P))?(w=l.charAt(P),P++):(w=c,ye===0&&Ce(X)),ye--,w===c&&(T=c,ye===0&&Ce(j)),w}o(nt,"peg$parsews");function uc(){var w,T;return ye++,Z.test(l.charAt(P))?(w=l.charAt(P),P++):(w=c,ye===0&&Ce(R)),ye--,w===c&&(T=c,ye===0&&Ce(J)),w}o(uc,"peg$parsecc");function fi(){var w,T;for(ye++,w=[],T=nt();T!==c;)w.push(T),T=nt();return ye--,w===c&&(T=c,ye===0&&Ce(A)),w}o(fi,"peg$parse__");function ll(){var w,T,W,U,wr,Kt;return w=P,T=Ur(),T!==c?(W=fi(),W!==c?(l.charCodeAt(P)===124?(U=I,P++):(U=c,ye===0&&Ce(G)),U!==c?(wr=fi(),wr!==c?(Kt=ll(),Kt!==c?(Re=w,T=K(T,Kt),w=T):(P=w,w=c)):(P=w,w=c)):(P=w,w=c)):(P=w,w=c)):(P=w,w=c),w===c&&(w=Ur()),w}o(ll,"peg$parseOrExpr");function Ur(){var w,T,W,U,wr,Kt;if(w=P,T=ra(),T!==c?(W=fi(),W!==c?(l.charCodeAt(P)===38?(U=se,P++):(U=c,ye===0&&Ce(ne)),U!==c?(wr=fi(),wr!==c?(Kt=Ur(),Kt!==c?(Re=w,T=pe(T,Kt),w=T):(P=w,w=c)):(P=w,w=c)):(P=w,w=c)):(P=w,w=c)):(P=w,w=c),w===c){if(w=P,T=ra(),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Ur(),U!==c?(Re=w,T=pe(T,U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;w===c&&(w=ra())}return w}o(Ur,"peg$parseAndExpr");function ra(){var w,T,W,U;return w=P,l.charCodeAt(P)===33?(T=me,P++):(T=c,ye===0&&Ce(xe)),T!==c?(W=fi(),W!==c?(U=ra(),U!==c?(Re=w,T=Ve(U),w=T):(P=w,w=c)):(P=w,w=c)):(P=w,w=c),w===c&&(w=jn()),w}o(ra,"peg$parseNotExpr");function jn(){var w,T,W,U,wr,Kt;return w=P,l.charCodeAt(P)===40?(T=tt,P++):(T=c,ye===0&&Ce(_e)),T!==c?(W=fi(),W!==c?(U=ll(),U!==c?(wr=fi(),wr!==c?(l.charCodeAt(P)===41?(Kt=St,P++):(Kt=c,ye===0&&Ce(We)),Kt!==c?(Re=w,T=Ke(U),w=T):(P=w,w=c)):(P=w,w=c)):(P=w,w=c)):(P=w,w=c)):(P=w,w=c),w===c&&(w=dd()),w}o(jn,"peg$parseBindingExpr");function dd(){var w,T,W,U;if(w=P,l.substr(P,4)===Ge?(T=Ge,P+=4):(T=c,ye===0&&Ce(Xe)),T!==c&&(Re=w,T=nr()),w=T,w===c&&(w=P,l.substr(P,2)===ct?(T=ct,P+=2):(T=c,ye===0&&Ce(Hr)),T!==c&&(Re=w,T=Zt()),w=T,w===c)){if(w=P,l.substr(P,2)===_t?(T=_t,P+=2):(T=c,ye===0&&Ce(Ct)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=ut(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,3)===Lr?(T=Lr,P+=3):(T=c,ye===0&&Ce(zt)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=$t(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,3)===ie?(T=ie,P+=3):(T=c,ye===0&&Ce(rt)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=Pr(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,2)===Gt?(T=Gt,P+=2):(T=c,ye===0&&Ce(Yt)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Mu(),U!==c?(Re=w,T=Se(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,8)===Or?(T=Or,P+=8):(T=c,ye===0&&Ce(fn)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=Un(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,2)===si?(T=si,P+=2):(T=c,ye===0&&Ce(cn)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=Jt(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c&&(w=P,l.substr(P,4)===gr?(T=gr,P+=4):(T=c,ye===0&&Ce(pt)),T!==c&&(Re=w,T=Ho()),w=T,w===c)){if(w=P,l.substr(P,4)===Cr?(T=Cr,P+=4):(T=c,ye===0&&Ce(Ui)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=pn(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c&&(w=P,l.substr(P,2)===zn?(T=zn,P+=2):(T=c,ye===0&&Ce(Si)),T!==c&&(Re=w,T=Ci()),w=T,w===c)){if(w=P,l.substr(P,2)===$n?(T=$n,P+=2):(T=c,ye===0&&Ce(Mn)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=Js(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,3)===H?(T=H,P+=3):(T=c,ye===0&&Ce(ee)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=he(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,3)===Te?(T=Te,P+=3):(T=c,ye===0&&Ce(ir)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=Ul(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c&&(w=P,l.substr(P,5)===Ft?(T=Ft,P+=5):(T=c,ye===0&&Ce(Wr)),T!==c&&(Re=w,T=or()),w=T,w===c&&(w=P,l.substr(P,7)===li?(T=li,P+=7):(T=c,ye===0&&Ce(ds)),T!==c&&(Re=w,T=lo()),w=T,w===c))){if(w=P,l.substr(P,7)===bi?(T=bi,P+=7):(T=c,ye===0&&Ce(el)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=hs(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,2)===dn?(T=dn,P+=2):(T=c,ye===0&&Ce(id)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=tl(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c&&(w=P,l.substr(P,2)===Qf?(T=Qf,P+=2):(T=c,ye===0&&Ce(rl)),T!==c&&(Re=w,T=od()),w=T,w===c&&(w=P,l.substr(P,8)===Zf?(T=Zf,P+=8):(T=c,ye===0&&Ce(wu)),T!==c&&(Re=w,T=sd()),w=T,w===c&&(w=P,l.substr(P,8)===zl?(T=zl,P+=8):(T=c,ye===0&&Ce(ms)),T!==c&&(Re=w,T=ld()),w=T,w===c&&(w=P,l.substr(P,7)===Jf?(T=Jf,P+=7):(T=c,ye===0&&Ce(nl)),T!==c&&(Re=w,T=xu()),w=T,w===c))))){if(w=P,l.substr(P,4)===Wo?(T=Wo,P+=4):(T=c,ye===0&&Ce(ad)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=Uo(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c&&(w=P,l.substr(P,2)===$l?(T=$l,P+=2):(T=c,ye===0&&Ce(ec)),T!==c&&(Re=w,T=jt()),w=T,w===c&&(w=P,l.substr(P,4)===Me?(T=Me,P+=4):(T=c,ye===0&&Ce(Ei)),T!==c&&(Re=w,T=Su()),w=T,w===c&&(w=P,l.substr(P,4)===ai?(T=ai,P+=4):(T=c,ye===0&&Ce(vt)),T!==c&&(Re=w,T=ao()),w=T,w===c)))){if(w=P,l.substr(P,3)===zo?(T=zo,P+=3):(T=c,ye===0&&Ce(jl)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=ue(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,3)===ze?(T=ze,P+=3):(T=c,ye===0&&Ce(Cu)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=bu(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,2)===gs?(T=gs,P+=2):(T=c,ye===0&&Ce(il)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=Eu(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.substr(P,2)===He?(T=He,P+=2):(T=c,ye===0&&Ce(ud)),T!==c){if(W=[],U=nt(),U!==c)for(;U!==c;)W.push(U),U=nt();else W=c;W!==c?(U=Vt(),U!==c?(Re=w,T=ql(U),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;w===c&&(w=P,l.substr(P,10)===uo?(T=uo,P+=10):(T=c,ye===0&&Ce(ui)),T!==c&&(Re=w,T=tc()),w=T,w===c&&(w=P,T=Vt(),T!==c&&(Re=w,T=ql(T)),w=T))}}}}}}}}}}}}}}}}}return w}o(dd,"peg$parseExpr");function Mu(){var w,T,W,U;if(ye++,w=P,$o.test(l.charAt(P))?(T=l.charAt(P),P++):(T=c,ye===0&&Ce(vs)),T===c&&(T=null),T!==c){if(W=[],Tu.test(l.charAt(P))?(U=l.charAt(P),P++):(U=c,ye===0&&Ce(ol)),U!==c)for(;U!==c;)W.push(U),Tu.test(l.charAt(P))?(U=l.charAt(P),P++):(U=c,ye===0&&Ce(ol));else W=c;W!==c?($o.test(l.charAt(P))?(U=l.charAt(P),P++):(U=c,ye===0&&Ce(vs)),U===c&&(U=null),U!==c?(Re=w,T=Vl(W),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;return ye--,w===c&&(T=c,ye===0&&Ce(_u)),w}o(Mu,"peg$parseIntegerLiteral");function Vt(){var w,T,W,U;if(ye++,w=P,l.charCodeAt(P)===34?(T=fo,P++):(T=c,ye===0&&Ce(Gl)),T!==c){for(W=[],U=xs();U!==c;)W.push(U),U=xs();W!==c?(l.charCodeAt(P)===34?(U=fo,P++):(U=c,ye===0&&Ce(Gl)),U!==c?(Re=w,T=Yl(W),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c){if(w=P,l.charCodeAt(P)===39?(T=rc,P++):(T=c,ye===0&&Ce(Xl)),T!==c){for(W=[],U=qo();U!==c;)W.push(U),U=qo();W!==c?(l.charCodeAt(P)===39?(U=rc,P++):(U=c,ye===0&&Ce(Xl)),U!==c?(Re=w,T=Yl(W),w=T):(P=w,w=c)):(P=w,w=c)}else P=w,w=c;if(w===c)if(w=P,T=P,ye++,W=uc(),ye--,W===c?T=void 0:(P=T,T=c),T!==c){if(W=[],U=yt(),U!==c)for(;U!==c;)W.push(U),U=yt();else W=c;W!==c?(Re=w,T=Yl(W),w=T):(P=w,w=c)}else P=w,w=c}return ye--,w===c&&(T=c,ye===0&&Ce(Kl)),w}o(Vt,"peg$parseStringLiteral");function xs(){var w,T,W;return w=P,T=P,ye++,_i.test(l.charAt(P))?(W=l.charAt(P),P++):(W=c,ye===0&&Ce(nc)),ye--,W===c?T=void 0:(P=T,T=c),T!==c?(l.length>P?(W=l.charAt(P),P++):(W=c,ye===0&&Ce(Ql)),W!==c?(Re=w,T=co(W),w=T):(P=w,w=c)):(P=w,w=c),w===c&&(w=P,l.charCodeAt(P)===92?(T=ys,P++):(T=c,ye===0&&Ce(ic)),T!==c?(W=$i(),W!==c?(Re=w,T=co(W),w=T):(P=w,w=c)):(P=w,w=c)),w}o(xs,"peg$parseDoubleStringChar");function qo(){var w,T,W;return w=P,T=P,ye++,oc.test(l.charAt(P))?(W=l.charAt(P),P++):(W=c,ye===0&&Ce(fd)),ye--,W===c?T=void 0:(P=T,T=c),T!==c?(l.length>P?(W=l.charAt(P),P++):(W=c,ye===0&&Ce(Ql)),W!==c?(Re=w,T=co(W),w=T):(P=w,w=c)):(P=w,w=c),w===c&&(w=P,l.charCodeAt(P)===92?(T=ys,P++):(T=c,ye===0&&Ce(ic)),T!==c?(W=$i(),W!==c?(Re=w,T=co(W),w=T):(P=w,w=c)):(P=w,w=c)),w}o(qo,"peg$parseSingleStringChar");function yt(){var w,T,W;return w=P,T=P,ye++,W=nt(),ye--,W===c?T=void 0:(P=T,T=c),T!==c?(l.length>P?(W=l.charAt(P),P++):(W=c,ye===0&&Ce(Ql)),W!==c?(Re=w,T=co(W),w=T):(P=w,w=c)):(P=w,w=c),w}o(yt,"peg$parseUnquotedStringChar");function $i(){var w,T;return cd.test(l.charAt(P))?(w=l.charAt(P),P++):(w=c,ye===0&&Ce(ku)),w===c&&(w=P,l.charCodeAt(P)===110?(T=sc,P++):(T=c,ye===0&&Ce(Nu)),T!==c&&(Re=w,T=lc()),w=T,w===c&&(w=P,l.charCodeAt(P)===114?(T=ac,P++):(T=c,ye===0&&Ce(Zl)),T!==c&&(Re=w,T=Jl()),w=T,w===c&&(w=P,l.charCodeAt(P)===116?(T=Lu,P++):(T=c,ye===0&&Ce(Ot)),T!==c&&(Re=w,T=Nt()),w=T))),w}o($i,"peg$parseEscapeSequence");function Au(w,T){function W(){return w.apply(this,arguments)||T.apply(this,arguments)}return o(W,"orFilter"),W.desc=w.desc+" or "+T.desc,W}o(Au,"or");function hd(w,T){function W(){return w.apply(this,arguments)&&T.apply(this,arguments)}return o(W,"andFilter"),W.desc=w.desc+" and "+T.desc,W}o(hd,"and");function Vo(w){function T(){return!w.apply(this,arguments)}return o(T,"notFilter"),T.desc="not "+w.desc,T}o(Vo,"not");function yr(w){function T(){return w.apply(this,arguments)}return o(T,"bindingFilter"),T.desc="("+w.desc+")",T}o(yr,"binding");function fc(w){return!0}o(fc,"allFilter"),fc.desc="all flows";var Du=[new RegExp("text/javascript"),new RegExp("application/x-javascript"),new RegExp("application/javascript"),new RegExp("text/css"),new RegExp("image/.*"),new RegExp("font/.*"),new RegExp("application/font.*")];function Ko(w){if(w.response){for(var T=Ys.getContentType(w.response),W=Du.length;W--;)if(Du[W].test(T))return!0}return!1}o(Ko,"assetFilter"),Ko.desc="is asset";function na(w){w=new RegExp(w,"i");function T(W){return!0}return o(T,"bodyFilter"),T.desc="body filters are not implemented yet, see https://github.com/mitmproxy/mitmproxy/issues/3609",T}o(na,"body");function Go(w){w=new RegExp(w,"i");function T(W){return!0}return o(T,"requestBodyFilter"),T.desc="body filters are not implemented yet, see https://github.com/mitmproxy/mitmproxy/issues/3609",T}o(Go,"requestBody");function md(w){w=new RegExp(w,"i");function T(W){return!0}return o(T,"responseBodyFilter"),T.desc="body filters are not implemented yet, see https://github.com/mitmproxy/mitmproxy/issues/3609",T}o(md,"responseBody");function ia(w){function T(W){return W.response&&W.response.status_code===w}return o(T,"responseCodeFilter"),T.desc="resp. code is "+w,T}o(ia,"responseCode");function Ru(w){w=new RegExp(w,"i");function T(W){return w.test(W.comment)}return o(T,"commentFilter"),T.desc="comment matches "+w,T}o(Ru,"comment");function Iu(w){w=new RegExp(w,"i");function T(W){return W.request&&(w.test(W.request.host)||w.test(W.request.pretty_host))}return o(T,"domainFilter"),T.desc="domain matches "+w,T}o(Iu,"domain");function oa(w){return w.type==="dns"}o(oa,"dnsFilter"),oa.desc="is a DNS Flow";function Fu(w){w=new RegExp(w,"i");function T(W){return!!W.server_conn.address&&w.test(W.server_conn.address[0]+":"+W.server_conn.address[1])}return o(T,"destinationFilter"),T.desc="destination address matches "+w,T}o(Fu,"destination");function Bu(w){return!!w.error}o(Bu,"errorFilter"),Bu.desc="has error";function Hu(w){w=new RegExp(w,"i");function T(W){return W.request&&Oo.match_header(W.request,w)||W.response&&Ys.match_header(W.response,w)}return o(T,"headerFilter"),T.desc="header matches "+w,T}o(Hu,"header");function Yo(w){w=new RegExp(w,"i");function T(W){return W.request&&Oo.match_header(W.request,w)}return o(T,"requestHeaderFilter"),T.desc="req. header matches "+w,T}o(Yo,"requestHeader");function ji(w){w=new RegExp(w,"i");function T(W){return W.response&&Ys.match_header(W.response,w)}return o(T,"responseHeaderFilter"),T.desc="resp. header matches "+w,T}o(ji,"responseHeader");function Ss(w){return w.type==="http"}o(Ss,"httpFilter"),Ss.desc="is an HTTP Flow";function zr(w){return w.marked}o(zr,"markedFilter"),zr.desc="is marked";function sa(w){w=new RegExp(w,"i");function T(W){return w.test(W.marked)}return o(T,"markerFilter"),T.desc="marker matches "+w,T}o(sa,"marker");function mn(w){w=new RegExp(w,"i");function T(W){return W.request&&w.test(W.request.method)}return o(T,"methodFilter"),T.desc="method matches "+w,T}o(mn,"method");function qi(w){return w.request&&!w.response}o(qi,"noResponseFilter"),qi.desc="has no response";function al(w){return w.is_replay==="request"}o(al,"clientReplayFilter"),al.desc="request has been replayed";function cc(w){return w.is_replay==="response"}o(cc,"serverReplayFilter"),cc.desc="response has been replayed";function Wu(w){return!!w.is_replay}o(Wu,"replayFilter"),Wu.desc="flow has been replayed";function gd(w){w=new RegExp(w,"i");function T(W){return!!W.client_conn.peername&&w.test(W.client_conn.peername[0]+":"+W.client_conn.peername[1])}return o(T,"sourceFilter"),T.desc="source address matches "+w,T}o(gd,"source");function Uu(w){return!!w.response}o(Uu,"responseFilter"),Uu.desc="has response";function la(w){return w.type==="tcp"}o(la,"tcpFilter"),la.desc="is a TCP Flow";function qn(w){return w.type==="udp"}o(qn,"udpFilter"),qn.desc="is a UDP Flow";function Ti(w){w=new RegExp(w,"i");function T(W){return W.request&&w.test(Oo.getContentType(W.request))}return o(T,"requestContentTypeFilter"),T.desc="req. content type matches "+w,T}o(Ti,"requestContentType");function pc(w){w=new RegExp(w,"i");function T(W){return W.response&&w.test(Ys.getContentType(W.response))}return o(T,"responseContentTypeFilter"),T.desc="resp. content type matches "+w,T}o(pc,"responseContentType");function aa(w){w=new RegExp(w,"i");function T(W){return W.request&&w.test(Oo.getContentType(W.request))||W.response&&w.test(Ys.getContentType(W.response))}return o(T,"contentTypeFilter"),T.desc="content type matches "+w,T}o(aa,"contentType");function dc(w){w=new RegExp(w,"i");function T(W){var U;if(W.type==="dns"){let wr=(U=W.request)==null?void 0:U.questions[0];return wr&&w.test(wr.name)}return W.request&&w.test(Oo.pretty_url(W.request))}return o(T,"urlFilter"),T.desc="url matches "+w,T}o(dc,"url");function Vi(w){return!!w.websocket}if(o(Vi,"websocketFilter"),Vi.desc="is a Websocket Flow",jo=C(),jo!==c&&P===l.length)return jo;throw jo!==c&&PwS,icon:()=>L0,method:()=>tm,path:()=>P0,quickactions:()=>Pp,size:()=>O0,status:()=>nm,time:()=>M0,timestamp:()=>A0,tls:()=>N0,version:()=>rm});var Xt=fe(Oe());var k0=fe(ti());var N0=o(({flow:e})=>Xt.default.createElement("td",{className:(0,k0.default)("col-tls",e.client_conn.tls_established?"col-tls-https":"col-tls-http")}),"tls");N0.headerName="";N0.sortKey=e=>e.type==="http"&&e.request.scheme;var L0=o(({flow:e})=>Xt.default.createElement("td",{className:"col-icon"},Xt.default.createElement("div",{className:(0,k0.default)("resource-icon",Gk(e))})),"icon");L0.headerName="";L0.sortKey=e=>Gk(e);var Gk=o(e=>{if(e.type!=="http")return e.client_conn.tls_version==="QUIC"?"resource-icon-quic":`resource-icon-${e.type}`;if(e.websocket)return"resource-icon-websocket";if(!e.response)return"resource-icon-plain";var t=Ys.getContentType(e.response)||"";return e.response.status_code===304?"resource-icon-not-modified":300<=e.response.status_code&&e.response.status_code<400?"resource-icon-redirect":t.indexOf("image")>=0?"resource-icon-image":t.indexOf("javascript")>=0?"resource-icon-js":t.indexOf("css")>=0?"resource-icon-css":t.indexOf("html")>=0?"resource-icon-document":"resource-icon-plain"},"getIcon"),Yk=o(e=>{var t,n,l,d;switch(e.type){case"http":return Oo.pretty_url(e.request);case"tcp":case"udp":return`${e.client_conn.peername.join(":")} \u2194 ${(n=(t=e.server_conn)==null?void 0:t.address)==null?void 0:n.join(":")}`;case"dns":return`${e.request.questions.map(h=>`${h.name} ${h.type}`).join(", ")} = ${((d=(l=e.response)==null?void 0:l.answers.map(h=>h.data).join(", "))!=null?d:"...")||"?"}`}},"mainPath"),P0=o(({flow:e})=>{let t;return e.error&&(e.error.msg==="Connection killed."?t=Xt.default.createElement("i",{className:"fa fa-fw fa-times pull-right"}):t=Xt.default.createElement("i",{className:"fa fa-fw fa-exclamation pull-right"})),Xt.default.createElement("td",{className:"col-path"},e.is_replay==="request"&&Xt.default.createElement("i",{className:"fa fa-fw fa-repeat pull-right"}),e.intercepted&&Xt.default.createElement("i",{className:"fa fa-fw fa-pause pull-right"}),t,Xt.default.createElement("span",{className:"marker pull-right"},e.marked),Yk(e))},"path");P0.headerName="Path";P0.sortKey=e=>Yk(e);var tm=o(({flow:e})=>Xt.default.createElement("td",{className:"col-method"},tm.sortKey(e)),"method");tm.headerName="Method";tm.sortKey=e=>{switch(e.type){case"http":return e.websocket?e.client_conn.tls_established?"WSS":"WS":e.request.method;case"dns":return e.request.op_code;default:return e.type.toUpperCase()}};var rm=o(({flow:e})=>Xt.default.createElement("td",{className:"col-http-version"},rm.sortKey(e)),"version");rm.headerName="Version";rm.sortKey=e=>{switch(e.type){case"http":return e.request.http_version;default:return""}};var nm=o(({flow:e})=>{let t="darkred";return e.type!=="http"&&e.type!="dns"||!e.response?Xt.default.createElement("td",{className:"col-status"}):(100<=e.response.status_code&&e.response.status_code<200?t="green":200<=e.response.status_code&&e.response.status_code<300?t="darkgreen":300<=e.response.status_code&&e.response.status_code<400?t="lightblue":(400<=e.response.status_code&&e.response.status_code<500||500<=e.response.status_code&&e.response.status_code<600)&&(t="red"),Xt.default.createElement("td",{className:"col-status",style:{color:t}},nm.sortKey(e)))},"status");nm.headerName="Status";nm.sortKey=e=>{var t,n;switch(e.type){case"http":return(t=e.response)==null?void 0:t.status_code;case"dns":return(n=e.response)==null?void 0:n.response_code;default:return}};var O0=o(({flow:e})=>Xt.default.createElement("td",{className:"col-size"},S0(yS(e))),"size");O0.headerName="Size";O0.sortKey=e=>yS(e);var M0=o(({flow:e})=>{let t=em(e),n=vS(e);return Xt.default.createElement("td",{className:"col-time"},t&&n?C0(1e3*(n-t)):"...")},"time");M0.headerName="Time";M0.sortKey=e=>{let t=em(e),n=vS(e);return t&&n&&n-t};var A0=o(({flow:e})=>{let t=em(e);return Xt.default.createElement("td",{className:"col-timestamp"},t?no(t):"...")},"timestamp");A0.headerName="Start time";A0.sortKey=e=>em(e);var Pp=o(({flow:e})=>{let t=Gs(),[n,l]=(0,Xt.useState)(!1),d=null;return e.intercepted?d=Xt.default.createElement("a",{href:"#",className:"quickaction",onClick:()=>t(Op(e))},Xt.default.createElement("i",{className:"fa fa-fw fa-play text-success"})):_0(e)&&(d=Xt.default.createElement("a",{href:"#",className:"quickaction",onClick:()=>t(Mp(e))},Xt.default.createElement("i",{className:"fa fa-fw fa-repeat text-primary"}))),Xt.default.createElement("td",{className:(0,k0.default)("col-quickactions",{hover:n}),onClick:()=>0},d?Xt.default.createElement("div",null,d):Xt.default.createElement(Xt.default.Fragment,null))},"quickactions");Pp.headerName="";Pp.sortKey=e=>0;var wS={icon:L0,method:tm,version:rm,path:P0,quickactions:Pp,size:O0,status:nm,time:M0,timestamp:A0,tls:N0};var _F="FLOWS_ADD",TF="FLOWS_UPDATE",Xk="FLOWS_REMOVE",kF="FLOWS_RECEIVE",Qk="FLOWS_SELECT",Zk="FLOWS_SET_FILTER",Jk="FLOWS_SET_SORT",eN="FLOWS_SET_HIGHLIGHT",NF=ke({highlight:void 0,filter:void 0,sort:{column:void 0,desc:!1},selected:[]},b0);function xS(e=NF,t){switch(t.type){case _F:case TF:case Xk:case kF:let n=Jh[t.cmd](t.data,tN(e.filter),SS(e.sort)),l=e.selected;if(t.type===Xk&&e.selected.includes(t.data)){if(e.selected.length>1)l=l.filter(d=>d!==t.data);else if(l=[],t.data in e.viewIndex&&e.view.length>1){let d=e.viewIndex[t.data],h;d===e.view.length-1?h=e.view[d-1]:h=e.view[d+1],l.push(h.id)}}return ke(Pt(ke({},e),{selected:l}),Lp(e,n));case Zk:return ke(Pt(ke({},e),{filter:t.filter}),Lp(e,dS(tN(t.filter),SS(e.sort))));case eN:return Pt(ke({},e),{highlight:t.highlight});case Jk:return ke(Pt(ke({},e),{sort:t.sort}),Lp(e,qk(SS(t.sort))));case Qk:return Pt(ke({},e),{selected:t.flowIds});default:return e}}o(xS,"reducer");function tN(e){if(!!e)return Of.parse(e)}o(tN,"makeFilter");function SS({column:e,desc:t}){if(!e)return(l,d)=>0;let n=wS[e].sortKey;return(l,d)=>{let h=n(l),c=n(d);return h>c?t?-1:1:hkt(`/flows/${e.id}/resume`,{method:"POST"})}o(Op,"resume");function I0(){return e=>kt("/flows/resume",{method:"POST"})}o(I0,"resumeAll");function F0(e){return t=>kt(`/flows/${e.id}/kill`,{method:"POST"})}o(F0,"kill");function nN(){return e=>kt("/flows/kill",{method:"POST"})}o(nN,"killAll");function B0(e){return t=>kt(`/flows/${e.id}`,{method:"DELETE"})}o(B0,"remove");function H0(e){return t=>kt(`/flows/${e.id}/duplicate`,{method:"POST"})}o(H0,"duplicate");function Mp(e){return t=>kt(`/flows/${e.id}/replay`,{method:"POST"})}o(Mp,"replay");function W0(e){return t=>kt(`/flows/${e.id}/revert`,{method:"POST"})}o(W0,"revert");function Wi(e,t){return n=>kt.put(`/flows/${e.id}`,t)}o(Wi,"update");function iN(e,t,n){let l=new FormData;return t=new window.Blob([t],{type:"plain/text"}),l.append("file",t),d=>kt(`/flows/${e.id}/${n}/content.data`,{method:"POST",body:l})}o(iN,"uploadContent");function U0(){return e=>kt("/clear",{method:"POST"})}o(U0,"clear");function oN(e){let t=new FormData;return t.append("file",e),n=>kt("/flows/dump",{method:"POST",body:t})}o(oN,"upload");function Af(e){return{type:Qk,flowIds:e?[e]:[]}}o(Af,"select");var z0="UI_HIDE_MODAL",sN="UI_SET_ACTIVE_MODAL",LF={activeModal:void 0};function CS(e=LF,t){switch(t.type){case sN:return Pt(ke({},e),{activeModal:t.activeModal});case z0:return Pt(ke({},e),{activeModal:void 0});default:return e}}o(CS,"reducer");function lN(e){return{type:sN,activeModal:e}}o(lN,"setActiveModal");function $0(){return{type:z0}}o($0,"hideModal");var wm=fe(Oe());var Ut=fe(Oe());var Dp=fe(Oe());var om=fe(Oe()),aN=fe(ti()),uN=(()=>{let e=document.createElement("div");return e.setAttribute("contenteditable","PLAINTEXT-ONLY"),e.contentEditable==="plaintext-only"?"plaintext-only":"true"})(),Ap=!1,Xs=class extends om.Component{constructor(){super(...arguments);this.input=om.default.createRef();this.isEditing=o(()=>{var t;return((t=this.input.current)==null?void 0:t.contentEditable)===uN},"isEditing");this.startEditing=o(()=>{if(!this.input.current)return console.error("unreachable");this.isEditing()||(this.suppress_events=!0,this.input.current.blur(),this.input.current.contentEditable=uN,window.requestAnimationFrame(()=>{var l,d;if(!this.input.current)return;this.input.current.focus(),this.suppress_events=!1;let t=document.createRange();t.selectNodeContents(this.input.current);let n=window.getSelection();n==null||n.removeAllRanges(),n==null||n.addRange(t),(d=(l=this.props).onEditStart)==null||d.call(l)}))},"startEditing");this.resetValue=o(()=>{var t,n;if(!this.input.current)return console.error("unreachable");this.input.current.textContent=this.props.content,(n=(t=this.props).onInput)==null||n.call(t,this.props.content)},"resetValue");this.finishEditing=o(()=>{if(!this.input.current)return console.error("unreachable");this.props.onEditDone(this.input.current.textContent||""),this.input.current.blur(),this.input.current.contentEditable="inherit"},"finishEditing");this.onPaste=o(t=>{t.preventDefault();let n=t.clipboardData.getData("text/plain");document.execCommand("insertHTML",!1,n)},"onPaste");this.suppress_events=!1;this.onMouseDown=o(t=>{Ap&&console.debug("onMouseDown",this.suppress_events),this.suppress_events=!0,window.addEventListener("mouseup",this.onMouseUp,{once:!0})},"onMouseDown");this.onMouseUp=o(t=>{var d;let n=t.target===this.input.current,l=!((d=window.getSelection())==null?void 0:d.toString());Ap&&console.warn("mouseUp",this.suppress_events,n,l),n&&l&&this.startEditing(),this.suppress_events=!1},"onMouseUp");this.onClick=o(t=>{Ap&&console.debug("onClick",this.suppress_events)},"onClick");this.onFocus=o(t=>{if(Ap&&console.debug("onFocus",this.props.content,this.suppress_events),!this.input.current)throw"unreachable";this.suppress_events||this.startEditing()},"onFocus");this.onInput=o(t=>{var n,l,d;(d=(l=this.props).onInput)==null||d.call(l,((n=this.input.current)==null?void 0:n.textContent)||"")},"onInput");this.onBlur=o(t=>{Ap&&console.debug("onBlur",this.props.content,this.suppress_events),!this.suppress_events&&this.finishEditing()},"onBlur");this.onKeyDown=o(t=>{var n,l;switch(Ap&&console.debug("keydown",t),t.stopPropagation(),t.key){case"Escape":t.preventDefault(),this.resetValue(),this.finishEditing();break;case"Enter":t.shiftKey||(t.preventDefault(),this.finishEditing());break;default:break}(l=(n=this.props).onKeyDown)==null||l.call(n,t)},"onKeyDown")}render(){let t=(0,aN.default)("inline-input",this.props.className);return om.default.createElement("span",{ref:this.input,tabIndex:0,className:t,placeholder:this.props.placeholder,onFocus:this.onFocus,onBlur:this.onBlur,onKeyDown:this.onKeyDown,onInput:this.onInput,onPaste:this.onPaste,onMouseDown:this.onMouseDown,onClick:this.onClick},this.props.content)}componentDidUpdate(t){var n,l;t.content!==this.props.content&&((l=(n=this.props).onInput)==null||l.call(n,this.props.content))}};o(Xs,"ValueEditor");var fN=fe(ti());function Df(e){let[t,n]=(0,Dp.useState)(e.isValid(e.content)),l=(0,Dp.useRef)(null),d=o(c=>{var v;e.isValid(c)?e.onEditDone(c):(v=l.current)==null||v.resetValue()},"onEditDone"),h=(0,fN.default)(e.className,t?"has-success":"has-warning");return Dp.default.createElement(Xs,Pt(ke({},e),{className:h,onInput:c=>n(e.isValid(c)),onEditDone:d,ref:l}))}o(Df,"ValidateEditor");function bS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}o(bS,"_defineProperty");function cN(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter(function(d){return Object.getOwnPropertyDescriptor(e,d).enumerable})),n.push.apply(n,l)}return n}o(cN,"ownKeys");function j0(e){for(var t=1;tn[l.level])));case hN:case MF:return ke(ke({},e),Lp(e,Jh[t.cmd](t.data,l=>e.filters[l.level])));default:return e}}o(kS,"reduce");function vN(e){return{type:gN,filter:e}}o(vN,"toggleFilter");function Rp(){return{type:mN}}o(Rp,"toggleVisibility");function yN(e,t="web"){let n={id:Math.random().toString(),message:e,level:t};return{type:hN,cmd:"add",data:n}}o(yN,"add");var wN="UI_OPTION_UPDATE_START",xN="UI_OPTION_UPDATE_SUCCESS",SN="UI_OPTION_UPDATE_ERROR",DF={};function NS(e=DF,t){switch(t.type){case wN:return Pt(ke({},e),{[t.option]:{isUpdating:!0,value:t.value,error:!1}});case xN:return Pt(ke({},e),{[t.option]:void 0});case SN:let n=e[t.option].value;return typeof n=="boolean"&&(n=!n),Pt(ke({},e),{[t.option]:{value:n,isUpdating:!1,error:t.error}});case z0:return{};default:return e}}o(NS,"reducer");function CN(e,t){return{type:wN,option:e,value:t}}o(CN,"startUpdate");function bN(e){return{type:xN,option:e}}o(bN,"updateSuccess");function EN(e,t){return{type:SN,option:e,error:t}}o(EN,"updateError");var _N=V0({flow:rS,modal:CS,optionsEditor:NS});var ni;(function(h){h.INIT="CONNECTION_INIT",h.FETCHING="CONNECTION_FETCHING",h.ESTABLISHED="CONNECTION_ESTABLISHED",h.ERROR="CONNECTION_ERROR",h.OFFLINE="CONNECTION_OFFLINE"})(ni||(ni={}));var RF={state:ni.INIT,message:void 0};function LS(e=RF,t){switch(t.type){case ni.ESTABLISHED:case ni.FETCHING:case ni.ERROR:case ni.OFFLINE:return{state:t.type,message:t.message};default:return e}}o(LS,"reducer");function TN(){return{type:ni.FETCHING}}o(TN,"startFetching");function kN(){return{type:ni.ESTABLISHED}}o(kN,"connectionEstablished");function NN(e){return{type:ni.ERROR,message:e}}o(NN,"connectionError");var LN={add_upstream_certs_to_client_chain:!1,allow_hosts:[],anticache:!1,anticomp:!1,block_global:!0,block_list:[],block_private:!1,body_size_limit:void 0,cert_passphrase:void 0,certs:[],ciphers_client:void 0,ciphers_server:void 0,client_certs:void 0,client_replay:[],client_replay_concurrency:1,command_history:!0,confdir:"~/.mitmproxy",connect_addr:void 0,connection_strategy:"eager",console_focus_follow:!1,content_view_lines_cutoff:512,export_preserve_original_ip:!1,hardump:"",http2:!0,http2_ping_keepalive:58,http3:!0,ignore_hosts:[],intercept:void 0,intercept_active:!1,keep_host_header:!1,key_size:2048,listen_host:"",listen_port:void 0,map_local:[],map_remote:[],mode:["regular"],modify_body:[],modify_headers:[],normalize_outbound_headers:!0,onboarding:!0,onboarding_host:"mitm.it",proxy_debug:!1,proxyauth:void 0,rawtcp:!0,readfile_filter:void 0,rfile:void 0,save_stream_file:void 0,save_stream_filter:void 0,scripts:[],server:!0,server_replay:[],server_replay_extra:"forward",server_replay_ignore_content:!1,server_replay_ignore_host:!1,server_replay_ignore_params:[],server_replay_ignore_payload_params:[],server_replay_ignore_port:!1,server_replay_kill_extra:!1,server_replay_nopop:!1,server_replay_refresh:!0,server_replay_reuse:!1,server_replay_use_headers:[],showhost:!1,ssl_insecure:!1,ssl_verify_upstream_trusted_ca:void 0,ssl_verify_upstream_trusted_confdir:void 0,stickyauth:void 0,stickycookie:void 0,stream_large_bodies:void 0,tcp_hosts:[],termlog_verbosity:"info",tls_ecdh_curve_client:void 0,tls_ecdh_curve_server:void 0,tls_version_client_max:"UNBOUNDED",tls_version_client_min:"TLS1_2",tls_version_server_max:"UNBOUNDED",tls_version_server_min:"TLS1_2",udp_hosts:[],upstream_auth:void 0,upstream_cert:!0,validate_inbound_headers:!0,view_filter:void 0,view_order:"time",view_order_reversed:!1,web_columns:["tls","icon","path","method","status","size","time"],web_debug:!1,web_host:"127.0.0.1",web_open_browser:!0,web_port:8081,web_static_viewer:"",websocket:!0};var PS="OPTIONS_RECEIVE",OS="OPTIONS_UPDATE";function MS(e=LN,t){switch(t.type){case PS:let n={};for(let[d,{value:h}]of Object.entries(t.data))n[d]=h;return n;case OS:let l=ke({},e);for(let[d,{value:h}]of Object.entries(t.data))l[d]=h;return l;default:return e}}o(MS,"reducer");function IF(e,t,n){return Ia(this,null,function*(){try{let l=yield kt.put("/options",{[e]:t});if(l.status===200)n(bN(e));else throw yield l.text()}catch(l){n(EN(e,l))}})}o(IF,"pureSendUpdate");var FF=IF;function Ip(e,t){return n=>{n(CN(e,t)),FF(e,t,n)}}o(Ip,"update");function PN(){return e=>kt("/options/save",{method:"POST"})}o(PN,"save");var ON="COMMANDBAR_TOGGLE_VISIBILITY",BF={visible:!1};function AS(e=BF,t){switch(t.type){case ON:return Pt(ke({},e),{visible:!e.visible});default:return e}}o(AS,"reducer");function K0(){return{type:ON}}o(K0,"toggleVisibility");function MN(e){return function(t){var n=t.dispatch,l=t.getState;return function(d){return function(h){return typeof h=="function"?h(n,l,e):d(h)}}}}o(MN,"createThunkMiddleware");var AN=MN();AN.withExtraArgument=MN;var DN=AN;var HF="STATE_RECEIVE",WF="STATE_UPDATE",UF={available:!1,version:"",contentViews:[],servers:[]};function DS(e=UF,t){switch(t.type){case HF:case WF:return ke(Pt(ke({},e),{available:!0}),t.data);default:return e}}o(DS,"reducer");var zF={},$F=o((e=zF,t)=>{switch(t.type){case PS:return t.data;case OS:return ke(ke({},e),t.data);default:return e}},"reducer"),RN=$F;var jF=window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__||TS,qF=V0({commandBar:AS,eventLog:kS,flows:xS,connection:LS,ui:_N,options:MS,options_meta:RN,backendState:DS}),VF=o(e=>_S(qF,e,jF(dN(DN))),"createAppStore"),Fp=VF(void 0),Qt=o(()=>Gs(),"useAppDispatch"),qe=eS;var io=fe(Oe());var IN=fe(Qh()),FN=fe(ti()),RS=class extends io.Component{constructor(){super(...arguments);this.container=io.default.createRef();this.nameInput=io.default.createRef();this.valueInput=io.default.createRef();this.render=o(()=>{let[t,n]=this.props.item;return io.default.createElement("div",{ref:this.container,className:"kv-row",onClick:this.onClick,onKeyDownCapture:this.onKeyDown},io.default.createElement(Xs,{ref:this.nameInput,className:"kv-key",content:t,onEditStart:this.props.onEditStart,onEditDone:l=>this.props.onEditDone([l,n])}),":\xA0",io.default.createElement(Xs,{ref:this.valueInput,className:"kv-value",content:n,onEditStart:this.props.onEditStart,onEditDone:l=>this.props.onEditDone([t,l]),placeholder:"empty"}))},"render");this.onClick=o(t=>{t.target===this.container.current&&this.props.onClickEmptyArea()},"onClick");this.onKeyDown=o(t=>{var n;t.target===((n=this.valueInput.current)==null?void 0:n.input.current)&&t.key==="Tab"&&this.props.onTabNext()},"onKeyDown")}};o(RS,"Row");var Bp=class extends io.Component{constructor(){super(...arguments);this.rowRefs={};this.state={currentList:this.props.data||[],initialList:this.props.data};this.render=o(()=>{this.rowRefs={};let t=this.state.currentList.map((n,l)=>io.default.createElement(RS,{key:l,item:n,onEditStart:()=>this.currentlyEditing=l,onEditDone:d=>this.onEditDone(l,d),onClickEmptyArea:()=>this.onClickEmptyArea(l),onTabNext:()=>this.onTabNext(l),ref:d=>this.rowRefs[l]=d}));return io.default.createElement("div",{className:(0,FN.default)("kv-editor",this.props.className),onMouseDown:this.onMouseDown},t,io.default.createElement("div",{onClick:n=>{n.preventDefault(),this.onClickEmptyArea(this.state.currentList.length-1)},className:"kv-add-row fa fa-plus-square-o",role:"button","aria-label":"Add"}))},"render");this.onEditDone=o((t,n)=>{let l=[...this.state.currentList];n[0]?l[t]=n:l.splice(t,1),this.currentlyEditing=void 0,(0,IN.isEqual)(this.state.currentList,l)||this.props.onChange(l),this.setState({currentList:l})},"onEditDone");this.onClickEmptyArea=o(t=>{if(this.justFinishedEditing)return;let n=[...this.state.currentList];n.splice(t+1,0,["",""]),this.setState({currentList:n},()=>{var l,d;return(d=(l=this.rowRefs[t+1])==null?void 0:l.nameInput.current)==null?void 0:d.startEditing()})},"onClickEmptyArea");this.onTabNext=o(t=>{t==this.state.currentList.length-1&&this.onClickEmptyArea(t)},"onTabNext");this.onMouseDown=o(t=>{this.justFinishedEditing=this.currentlyEditing},"onMouseDown")}static getDerivedStateFromProps(t,n){return t.data!==n.initialList?{currentList:t.data||[],initialList:t.data}:null}};o(Bp,"KeyValueListEditor");var tr=fe(Oe());var sm=fe(Oe());function G0(e,t){let[n,l]=(0,sm.useState)(),[d,h]=(0,sm.useState)();return(0,sm.useEffect)(()=>{d&&d.abort();let c=new AbortController;return kt(e,{signal:c.signal}).then(v=>{if(!v.ok)throw`${v.status} ${v.statusText}`.trim();return v.text()}).then(v=>{l(v)}).catch(v=>{c.signal.aborted||l(`Error getting content: ${v}.`)}),h(c),()=>{c.signal.aborted||c.abort()}},[e,t]),n}o(G0,"useContent");var lm=fe(Oe()),Y0=lm.default.memo(o(function({icon:t,text:n,className:l,title:d,onOpenFile:h,onClick:c}){let v;return lm.default.createElement("a",{href:"#",onClick:C=>{v.click(),c&&c(C)},className:l,title:d},lm.default.createElement("i",{className:"fa fa-fw "+t}),n,lm.default.createElement("input",{ref:C=>v=C,className:"hidden",type:"file",onChange:C=>{C.preventDefault(),C.target.files&&C.target.files.length>0&&h(C.target.files[0]),v.value=""}}))},"FileChooser"));var Hp=fe(Oe()),BN=fe(ti());function kr({onClick:e,children:t,icon:n,disabled:l,className:d,title:h}){return Hp.createElement("button",{className:(0,BN.default)(d,"btn btn-default"),onClick:l?void 0:e,disabled:l,title:h},n&&Hp.createElement(Hp.Fragment,null,Hp.createElement("i",{className:"fa "+n}),"\xA0"),t)}o(kr,"Button");var um=fe(Oe()),jN=fe(Oe());var am=fe(Oe()),WN=fe(ti()),UN=fe(HN()),zN=fe(Qh());function $N(e){return e&&e.replace(/\r\n|\r/g,` -`)}o($N,"normalizeLineEndings");var Wp=class extends am.Component{constructor(t){super(t);this.state={isFocused:!1}}getCodeMirrorInstance(){return this.props.codeMirrorInstance||UN.default}UNSAFE_componentWillMount(){this.props.path&&console.error("Warning: react-codemirror: the `path` prop has been changed to `name`")}componentDidMount(){let t=this.getCodeMirrorInstance();this.codeMirror=t.fromTextArea(this.textareaNode,this.props.options),this.codeMirror.on("change",this.codemirrorValueChanged.bind(this)),this.codeMirror.on("cursorActivity",this.cursorActivity.bind(this)),this.codeMirror.on("focus",this.focusChanged.bind(this,!0)),this.codeMirror.on("blur",this.focusChanged.bind(this,!1)),this.codeMirror.on("scroll",this.scrollChanged.bind(this)),this.codeMirror.setValue(this.props.defaultValue||this.props.value||"")}componentWillUnmount(){this.codeMirror&&this.codeMirror.toTextArea()}UNSAFE_componentWillReceiveProps(t){if(this.codeMirror&&t.value!==void 0&&t.value!==this.props.value&&$N(this.codeMirror.getValue())!==$N(t.value))if(this.props.preserveScrollPosition){var n=this.codeMirror.getScrollInfo();this.codeMirror.setValue(t.value),this.codeMirror.scrollTo(n.left,n.top)}else this.codeMirror.setValue(t.value);if(typeof t.options=="object")for(let l in t.options)t.options.hasOwnProperty(l)&&this.setOptionIfChanged(l,t.options[l])}setOptionIfChanged(t,n){let l=this.codeMirror.getOption(t);zN.default.isEqual(l,n)||this.codeMirror.setOption(t,n)}getCodeMirror(){return this.codeMirror}focus(){this.codeMirror&&this.codeMirror.focus()}focusChanged(t){this.setState({isFocused:t}),this.props.onFocusChange&&this.props.onFocusChange(t)}cursorActivity(t){this.props.onCursorActivity&&this.props.onCursorActivity(t)}scrollChanged(t){this.props.onScroll&&this.props.onScroll(t.getScrollInfo())}codemirrorValueChanged(t,n){this.props.onChange&&n.origin!=="setValue"&&this.props.onChange(t.getValue(),n)}render(){let t=(0,WN.default)("ReactCodeMirror",this.state.isFocused?"ReactCodeMirror--focused":null,this.props.className);return am.createElement("div",{className:t},am.createElement("textarea",{ref:n=>this.textareaNode=n,name:this.props.name||this.props.path,defaultValue:this.props.value,autoComplete:"off",autoFocus:this.props.autoFocus}))}};o(Wp,"CodeMirror"),Wp.defaultProps={preserveScrollPosition:!1};var fm=class extends jN.Component{constructor(){super(...arguments);this.editor=um.createRef();this.getContent=o(()=>{var t;return(t=this.editor.current)==null?void 0:t.codeMirror.getValue()},"getContent");this.render=o(()=>{let t={lineNumbers:!0};return um.createElement("div",{className:"codeeditor",onKeyDown:n=>n.stopPropagation()},um.createElement(Wp,{ref:this.editor,value:this.props.initialContent,onChange:()=>0,options:t}))},"render")}};o(fm,"CodeEditor");var Rf=fe(Oe()),KF=Rf.default.memo(o(function({lines:t,maxLines:n,showMore:l}){return t.length===0?null:Rf.default.createElement("pre",null,t.map((d,h)=>h===n?Rf.default.createElement("button",{key:"showmore",onClick:l,className:"btn btn-xs btn-info"},Rf.default.createElement("i",{className:"fa fa-angle-double-down","aria-hidden":"true"})," ","Show more"):Rf.default.createElement("div",{key:h},d.map(([c,v],C)=>Rf.default.createElement("span",{key:C,className:c},v)))))},"LineRenderer")),X0=KF;var zf=fe(Oe());var xi=fe(Oe());var Q0=fe(Oe());var BS=o(function(t){return t.reduce(function(n,l){var d=l[0],h=l[1];return n[d]=h,n},{})},"fromEntries"),HS=typeof window!="undefined"&&window.document&&window.document.createElement?Q0.useLayoutEffect:Q0.useEffect;var fu=fe(Oe());var Gr="top",Ln="bottom",ln="right",an="left",Z0="auto",su=[Gr,Ln,ln,an],Rl="start",J0="end",qN="clippingParents",ey="viewport",Up="popper",VN="reference",WS=su.reduce(function(e,t){return e.concat([t+"-"+Rl,t+"-"+J0])},[]),ty=[].concat(su,[Z0]).reduce(function(e,t){return e.concat([t,t+"-"+Rl,t+"-"+J0])},[]),GF="beforeRead",YF="read",XF="afterRead",QF="beforeMain",ZF="main",JF="afterMain",e3="beforeWrite",t3="write",r3="afterWrite",KN=[GF,YF,XF,QF,ZF,JF,e3,t3,r3];function Pn(e){return e?(e.nodeName||"").toLowerCase():null}o(Pn,"getNodeName");function Br(e){if(e==null)return window;if(e.toString()!=="[object Window]"){var t=e.ownerDocument;return t&&t.defaultView||window}return e}o(Br,"getWindow");function Il(e){var t=Br(e).Element;return e instanceof t||e instanceof Element}o(Il,"isElement");function Yr(e){var t=Br(e).HTMLElement;return e instanceof t||e instanceof HTMLElement}o(Yr,"isHTMLElement");function ry(e){if(typeof ShadowRoot=="undefined")return!1;var t=Br(e).ShadowRoot;return e instanceof t||e instanceof ShadowRoot}o(ry,"isShadowRoot");function n3(e){var t=e.state;Object.keys(t.elements).forEach(function(n){var l=t.styles[n]||{},d=t.attributes[n]||{},h=t.elements[n];!Yr(h)||!Pn(h)||(Object.assign(h.style,l),Object.keys(d).forEach(function(c){var v=d[c];v===!1?h.removeAttribute(c):h.setAttribute(c,v===!0?"":v)}))})}o(n3,"applyStyles");function i3(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach(function(l){var d=t.elements[l],h=t.attributes[l]||{},c=Object.keys(t.styles.hasOwnProperty(l)?t.styles[l]:n[l]),v=c.reduce(function(C,k){return C[k]="",C},{});!Yr(d)||!Pn(d)||(Object.assign(d.style,v),Object.keys(h).forEach(function(C){d.removeAttribute(C)}))})}}o(i3,"effect");var GN={name:"applyStyles",enabled:!0,phase:"write",fn:n3,effect:i3,requires:["computeStyles"]};function On(e){return e.split("-")[0]}o(On,"getBasePlacement");var lu=Math.round;function Mo(e,t){t===void 0&&(t=!1);var n=e.getBoundingClientRect(),l=1,d=1;return Yr(e)&&t&&(l=n.width/e.offsetWidth||1,d=n.height/e.offsetHeight||1),{width:lu(n.width/l),height:lu(n.height/d),top:lu(n.top/d),right:lu(n.right/l),bottom:lu(n.bottom/d),left:lu(n.left/l),x:lu(n.left/l),y:lu(n.top/d)}}o(Mo,"getBoundingClientRect");function If(e){var t=Mo(e),n=e.offsetWidth,l=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-l)<=1&&(l=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:l}}o(If,"getLayoutRect");function cm(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&ry(n)){var l=t;do{if(l&&e.isSameNode(l))return!0;l=l.parentNode||l.host}while(l)}return!1}o(cm,"contains");function wi(e){return Br(e).getComputedStyle(e)}o(wi,"getComputedStyle");function US(e){return["table","td","th"].indexOf(Pn(e))>=0}o(US,"isTableElement");function Bn(e){return((Il(e)?e.ownerDocument:e.document)||window.document).documentElement}o(Bn,"getDocumentElement");function Fl(e){return Pn(e)==="html"?e:e.assignedSlot||e.parentNode||(ry(e)?e.host:null)||Bn(e)}o(Fl,"getParentNode");function YN(e){return!Yr(e)||wi(e).position==="fixed"?null:e.offsetParent}o(YN,"getTrueOffsetParent");function o3(e){var t=navigator.userAgent.toLowerCase().indexOf("firefox")!==-1,n=navigator.userAgent.indexOf("Trident")!==-1;if(n&&Yr(e)){var l=wi(e);if(l.position==="fixed")return null}for(var d=Fl(e);Yr(d)&&["html","body"].indexOf(Pn(d))<0;){var h=wi(d);if(h.transform!=="none"||h.perspective!=="none"||h.contain==="paint"||["transform","perspective"].indexOf(h.willChange)!==-1||t&&h.willChange==="filter"||t&&h.filter&&h.filter!=="none")return d;d=d.parentNode}return null}o(o3,"getContainingBlock");function as(e){for(var t=Br(e),n=YN(e);n&&US(n)&&wi(n).position==="static";)n=YN(n);return n&&(Pn(n)==="html"||Pn(n)==="body"&&wi(n).position==="static")?t:n||o3(e)||t}o(as,"getOffsetParent");function Ff(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}o(Ff,"getMainAxisFromPlacement");var Ao=Math.max,au=Math.min,pm=Math.round;function Bf(e,t,n){return Ao(e,au(t,n))}o(Bf,"within");function dm(){return{top:0,right:0,bottom:0,left:0}}o(dm,"getFreshSideObject");function hm(e){return Object.assign({},dm(),e)}o(hm,"mergePaddingObject");function mm(e,t){return t.reduce(function(n,l){return n[l]=e,n},{})}o(mm,"expandToHashMap");var s3=o(function(t,n){return t=typeof t=="function"?t(Object.assign({},n.rects,{placement:n.placement})):t,hm(typeof t!="number"?t:mm(t,su))},"toPaddingObject");function l3(e){var t,n=e.state,l=e.name,d=e.options,h=n.elements.arrow,c=n.modifiersData.popperOffsets,v=On(n.placement),C=Ff(v),k=[an,ln].indexOf(v)>=0,O=k?"height":"width";if(!(!h||!c)){var j=s3(d.padding,n),B=If(h),X=C==="y"?Gr:an,J=C==="y"?Ln:ln,Z=n.rects.reference[O]+n.rects.reference[C]-c[C]-n.rects.popper[O],R=c[C]-n.rects.reference[C],A=as(h),I=A?C==="y"?A.clientHeight||0:A.clientWidth||0:0,G=Z/2-R/2,K=j[X],se=I-B[O]-j[J],ne=I/2-B[O]/2+G,pe=Bf(K,ne,se),me=C;n.modifiersData[l]=(t={},t[me]=pe,t.centerOffset=pe-ne,t)}}o(l3,"arrow");function a3(e){var t=e.state,n=e.options,l=n.element,d=l===void 0?"[data-popper-arrow]":l;d!=null&&(typeof d=="string"&&(d=t.elements.popper.querySelector(d),!d)||!cm(t.elements.popper,d)||(t.elements.arrow=d))}o(a3,"effect");var XN={name:"arrow",enabled:!0,phase:"main",fn:l3,effect:a3,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};var u3={top:"auto",right:"auto",bottom:"auto",left:"auto"};function f3(e){var t=e.x,n=e.y,l=window,d=l.devicePixelRatio||1;return{x:pm(pm(t*d)/d)||0,y:pm(pm(n*d)/d)||0}}o(f3,"roundOffsetsByDPR");function QN(e){var t,n=e.popper,l=e.popperRect,d=e.placement,h=e.offsets,c=e.position,v=e.gpuAcceleration,C=e.adaptive,k=e.roundOffsets,O=k===!0?f3(h):typeof k=="function"?k(h):h,j=O.x,B=j===void 0?0:j,X=O.y,J=X===void 0?0:X,Z=h.hasOwnProperty("x"),R=h.hasOwnProperty("y"),A=an,I=Gr,G=window;if(C){var K=as(n),se="clientHeight",ne="clientWidth";K===Br(n)&&(K=Bn(n),wi(K).position!=="static"&&(se="scrollHeight",ne="scrollWidth")),K=K,d===Gr&&(I=Ln,J-=K[se]-l.height,J*=v?1:-1),d===an&&(A=ln,B-=K[ne]-l.width,B*=v?1:-1)}var pe=Object.assign({position:c},C&&u3);if(v){var me;return Object.assign({},pe,(me={},me[I]=R?"0":"",me[A]=Z?"0":"",me.transform=(G.devicePixelRatio||1)<2?"translate("+B+"px, "+J+"px)":"translate3d("+B+"px, "+J+"px, 0)",me))}return Object.assign({},pe,(t={},t[I]=R?J+"px":"",t[A]=Z?B+"px":"",t.transform="",t))}o(QN,"mapToStyles");function c3(e){var t=e.state,n=e.options,l=n.gpuAcceleration,d=l===void 0?!0:l,h=n.adaptive,c=h===void 0?!0:h,v=n.roundOffsets,C=v===void 0?!0:v;if(!1)var k;var O={placement:On(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:d};t.modifiersData.popperOffsets!=null&&(t.styles.popper=Object.assign({},t.styles.popper,QN(Object.assign({},O,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:c,roundOffsets:C})))),t.modifiersData.arrow!=null&&(t.styles.arrow=Object.assign({},t.styles.arrow,QN(Object.assign({},O,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:C})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})}o(c3,"computeStyles");var ZN={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:c3,data:{}};var ny={passive:!0};function p3(e){var t=e.state,n=e.instance,l=e.options,d=l.scroll,h=d===void 0?!0:d,c=l.resize,v=c===void 0?!0:c,C=Br(t.elements.popper),k=[].concat(t.scrollParents.reference,t.scrollParents.popper);return h&&k.forEach(function(O){O.addEventListener("scroll",n.update,ny)}),v&&C.addEventListener("resize",n.update,ny),function(){h&&k.forEach(function(O){O.removeEventListener("scroll",n.update,ny)}),v&&C.removeEventListener("resize",n.update,ny)}}o(p3,"effect");var JN={name:"eventListeners",enabled:!0,phase:"write",fn:o(function(){},"fn"),effect:p3,data:{}};var d3={left:"right",right:"left",bottom:"top",top:"bottom"};function zp(e){return e.replace(/left|right|bottom|top/g,function(t){return d3[t]})}o(zp,"getOppositePlacement");var h3={start:"end",end:"start"};function iy(e){return e.replace(/start|end/g,function(t){return h3[t]})}o(iy,"getOppositeVariationPlacement");function Hf(e){var t=Br(e),n=t.pageXOffset,l=t.pageYOffset;return{scrollLeft:n,scrollTop:l}}o(Hf,"getWindowScroll");function Wf(e){return Mo(Bn(e)).left+Hf(e).scrollLeft}o(Wf,"getWindowScrollBarX");function zS(e){var t=Br(e),n=Bn(e),l=t.visualViewport,d=n.clientWidth,h=n.clientHeight,c=0,v=0;return l&&(d=l.width,h=l.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(c=l.offsetLeft,v=l.offsetTop)),{width:d,height:h,x:c+Wf(e),y:v}}o(zS,"getViewportRect");function $S(e){var t,n=Bn(e),l=Hf(e),d=(t=e.ownerDocument)==null?void 0:t.body,h=Ao(n.scrollWidth,n.clientWidth,d?d.scrollWidth:0,d?d.clientWidth:0),c=Ao(n.scrollHeight,n.clientHeight,d?d.scrollHeight:0,d?d.clientHeight:0),v=-l.scrollLeft+Wf(e),C=-l.scrollTop;return wi(d||n).direction==="rtl"&&(v+=Ao(n.clientWidth,d?d.clientWidth:0)-h),{width:h,height:c,x:v,y:C}}o($S,"getDocumentRect");function Uf(e){var t=wi(e),n=t.overflow,l=t.overflowX,d=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+d+l)}o(Uf,"isScrollParent");function oy(e){return["html","body","#document"].indexOf(Pn(e))>=0?e.ownerDocument.body:Yr(e)&&Uf(e)?e:oy(Fl(e))}o(oy,"getScrollParent");function uu(e,t){var n;t===void 0&&(t=[]);var l=oy(e),d=l===((n=e.ownerDocument)==null?void 0:n.body),h=Br(l),c=d?[h].concat(h.visualViewport||[],Uf(l)?l:[]):l,v=t.concat(c);return d?v:v.concat(uu(Fl(c)))}o(uu,"listScrollParents");function $p(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}o($p,"rectToClientRect");function m3(e){var t=Mo(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}o(m3,"getInnerBoundingClientRect");function eL(e,t){return t===ey?$p(zS(e)):Yr(t)?m3(t):$p($S(Bn(e)))}o(eL,"getClientRectFromMixedType");function g3(e){var t=uu(Fl(e)),n=["absolute","fixed"].indexOf(wi(e).position)>=0,l=n&&Yr(e)?as(e):e;return Il(l)?t.filter(function(d){return Il(d)&&cm(d,l)&&Pn(d)!=="body"}):[]}o(g3,"getClippingParents");function jS(e,t,n){var l=t==="clippingParents"?g3(e):[].concat(t),d=[].concat(l,[n]),h=d[0],c=d.reduce(function(v,C){var k=eL(e,C);return v.top=Ao(k.top,v.top),v.right=au(k.right,v.right),v.bottom=au(k.bottom,v.bottom),v.left=Ao(k.left,v.left),v},eL(e,h));return c.width=c.right-c.left,c.height=c.bottom-c.top,c.x=c.left,c.y=c.top,c}o(jS,"getClippingRect");function Qs(e){return e.split("-")[1]}o(Qs,"getVariation");function gm(e){var t=e.reference,n=e.element,l=e.placement,d=l?On(l):null,h=l?Qs(l):null,c=t.x+t.width/2-n.width/2,v=t.y+t.height/2-n.height/2,C;switch(d){case Gr:C={x:c,y:t.y-n.height};break;case Ln:C={x:c,y:t.y+t.height};break;case ln:C={x:t.x+t.width,y:v};break;case an:C={x:t.x-n.width,y:v};break;default:C={x:t.x,y:t.y}}var k=d?Ff(d):null;if(k!=null){var O=k==="y"?"height":"width";switch(h){case Rl:C[k]=C[k]-(t[O]/2-n[O]/2);break;case J0:C[k]=C[k]+(t[O]/2-n[O]/2);break;default:}}return C}o(gm,"computeOffsets");function us(e,t){t===void 0&&(t={});var n=t,l=n.placement,d=l===void 0?e.placement:l,h=n.boundary,c=h===void 0?qN:h,v=n.rootBoundary,C=v===void 0?ey:v,k=n.elementContext,O=k===void 0?Up:k,j=n.altBoundary,B=j===void 0?!1:j,X=n.padding,J=X===void 0?0:X,Z=hm(typeof J!="number"?J:mm(J,su)),R=O===Up?VN:Up,A=e.elements.reference,I=e.rects.popper,G=e.elements[B?R:O],K=jS(Il(G)?G:G.contextElement||Bn(e.elements.popper),c,C),se=Mo(A),ne=gm({reference:se,element:I,strategy:"absolute",placement:d}),pe=$p(Object.assign({},I,ne)),me=O===Up?pe:se,xe={top:K.top-me.top+Z.top,bottom:me.bottom-K.bottom+Z.bottom,left:K.left-me.left+Z.left,right:me.right-K.right+Z.right},Ve=e.modifiersData.offset;if(O===Up&&Ve){var tt=Ve[d];Object.keys(xe).forEach(function(_e){var St=[ln,Ln].indexOf(_e)>=0?1:-1,We=[Gr,Ln].indexOf(_e)>=0?"y":"x";xe[_e]+=tt[We]*St})}return xe}o(us,"detectOverflow");function qS(e,t){t===void 0&&(t={});var n=t,l=n.placement,d=n.boundary,h=n.rootBoundary,c=n.padding,v=n.flipVariations,C=n.allowedAutoPlacements,k=C===void 0?ty:C,O=Qs(l),j=O?v?WS:WS.filter(function(J){return Qs(J)===O}):su,B=j.filter(function(J){return k.indexOf(J)>=0});B.length===0&&(B=j);var X=B.reduce(function(J,Z){return J[Z]=us(e,{placement:Z,boundary:d,rootBoundary:h,padding:c})[On(Z)],J},{});return Object.keys(X).sort(function(J,Z){return X[J]-X[Z]})}o(qS,"computeAutoPlacement");function v3(e){if(On(e)===Z0)return[];var t=zp(e);return[iy(e),t,iy(t)]}o(v3,"getExpandedFallbackPlacements");function y3(e){var t=e.state,n=e.options,l=e.name;if(!t.modifiersData[l]._skip){for(var d=n.mainAxis,h=d===void 0?!0:d,c=n.altAxis,v=c===void 0?!0:c,C=n.fallbackPlacements,k=n.padding,O=n.boundary,j=n.rootBoundary,B=n.altBoundary,X=n.flipVariations,J=X===void 0?!0:X,Z=n.allowedAutoPlacements,R=t.options.placement,A=On(R),I=A===R,G=C||(I||!J?[zp(R)]:v3(R)),K=[R].concat(G).reduce(function(ut,Lr){return ut.concat(On(Lr)===Z0?qS(t,{placement:Lr,boundary:O,rootBoundary:j,padding:k,flipVariations:J,allowedAutoPlacements:Z}):Lr)},[]),se=t.rects.reference,ne=t.rects.popper,pe=new Map,me=!0,xe=K[0],Ve=0;Ve=0,Ke=We?"width":"height",Ge=us(t,{placement:tt,boundary:O,rootBoundary:j,altBoundary:B,padding:k}),Xe=We?St?ln:an:St?Ln:Gr;se[Ke]>ne[Ke]&&(Xe=zp(Xe));var nr=zp(Xe),ct=[];if(h&&ct.push(Ge[_e]<=0),v&&ct.push(Ge[Xe]<=0,Ge[nr]<=0),ct.every(function(ut){return ut})){xe=tt,me=!1;break}pe.set(tt,ct)}if(me)for(var Hr=J?3:1,Zt=o(function(Lr){var zt=K.find(function($t){var ie=pe.get($t);if(ie)return ie.slice(0,Lr).every(function(rt){return rt})});if(zt)return xe=zt,"break"},"_loop"),_t=Hr;_t>0;_t--){var Ct=Zt(_t);if(Ct==="break")break}t.placement!==xe&&(t.modifiersData[l]._skip=!0,t.placement=xe,t.reset=!0)}}o(y3,"flip");var tL={name:"flip",enabled:!0,phase:"main",fn:y3,requiresIfExists:["offset"],data:{_skip:!1}};function rL(e,t,n){return n===void 0&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}o(rL,"getSideOffsets");function nL(e){return[Gr,ln,Ln,an].some(function(t){return e[t]>=0})}o(nL,"isAnySideFullyClipped");function w3(e){var t=e.state,n=e.name,l=t.rects.reference,d=t.rects.popper,h=t.modifiersData.preventOverflow,c=us(t,{elementContext:"reference"}),v=us(t,{altBoundary:!0}),C=rL(c,l),k=rL(v,d,h),O=nL(C),j=nL(k);t.modifiersData[n]={referenceClippingOffsets:C,popperEscapeOffsets:k,isReferenceHidden:O,hasPopperEscaped:j},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":O,"data-popper-escaped":j})}o(w3,"hide");var iL={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:w3};function x3(e,t,n){var l=On(e),d=[an,Gr].indexOf(l)>=0?-1:1,h=typeof n=="function"?n(Object.assign({},t,{placement:e})):n,c=h[0],v=h[1];return c=c||0,v=(v||0)*d,[an,ln].indexOf(l)>=0?{x:v,y:c}:{x:c,y:v}}o(x3,"distanceAndSkiddingToXY");function S3(e){var t=e.state,n=e.options,l=e.name,d=n.offset,h=d===void 0?[0,0]:d,c=ty.reduce(function(O,j){return O[j]=x3(j,t.rects,h),O},{}),v=c[t.placement],C=v.x,k=v.y;t.modifiersData.popperOffsets!=null&&(t.modifiersData.popperOffsets.x+=C,t.modifiersData.popperOffsets.y+=k),t.modifiersData[l]=c}o(S3,"offset");var oL={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:S3};function C3(e){var t=e.state,n=e.name;t.modifiersData[n]=gm({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})}o(C3,"popperOffsets");var sL={name:"popperOffsets",enabled:!0,phase:"read",fn:C3,data:{}};function VS(e){return e==="x"?"y":"x"}o(VS,"getAltAxis");function b3(e){var t=e.state,n=e.options,l=e.name,d=n.mainAxis,h=d===void 0?!0:d,c=n.altAxis,v=c===void 0?!1:c,C=n.boundary,k=n.rootBoundary,O=n.altBoundary,j=n.padding,B=n.tether,X=B===void 0?!0:B,J=n.tetherOffset,Z=J===void 0?0:J,R=us(t,{boundary:C,rootBoundary:k,padding:j,altBoundary:O}),A=On(t.placement),I=Qs(t.placement),G=!I,K=Ff(A),se=VS(K),ne=t.modifiersData.popperOffsets,pe=t.rects.reference,me=t.rects.popper,xe=typeof Z=="function"?Z(Object.assign({},t.rects,{placement:t.placement})):Z,Ve={x:0,y:0};if(!!ne){if(h||v){var tt=K==="y"?Gr:an,_e=K==="y"?Ln:ln,St=K==="y"?"height":"width",We=ne[K],Ke=ne[K]+R[tt],Ge=ne[K]-R[_e],Xe=X?-me[St]/2:0,nr=I===Rl?pe[St]:me[St],ct=I===Rl?-me[St]:-pe[St],Hr=t.elements.arrow,Zt=X&&Hr?If(Hr):{width:0,height:0},_t=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:dm(),Ct=_t[tt],ut=_t[_e],Lr=Bf(0,pe[St],Zt[St]),zt=G?pe[St]/2-Xe-Lr-Ct-xe:nr-Lr-Ct-xe,$t=G?-pe[St]/2+Xe+Lr+ut+xe:ct+Lr+ut+xe,ie=t.elements.arrow&&as(t.elements.arrow),rt=ie?K==="y"?ie.clientTop||0:ie.clientLeft||0:0,Pr=t.modifiersData.offset?t.modifiersData.offset[t.placement][K]:0,Gt=ne[K]+zt-Pr-rt,Yt=ne[K]+$t-Pr;if(h){var Se=Bf(X?au(Ke,Gt):Ke,We,X?Ao(Ge,Yt):Ge);ne[K]=Se,Ve[K]=Se-We}if(v){var Or=K==="x"?Gr:an,fn=K==="x"?Ln:ln,Un=ne[se],si=Un+R[Or],cn=Un-R[fn],Jt=Bf(X?au(si,Gt):si,Un,X?Ao(cn,Yt):cn);ne[se]=Jt,Ve[se]=Jt-Un}}t.modifiersData[l]=Ve}}o(b3,"preventOverflow");var lL={name:"preventOverflow",enabled:!0,phase:"main",fn:b3,requiresIfExists:["offset"]};function KS(e){return{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}}o(KS,"getHTMLElementScroll");function GS(e){return e===Br(e)||!Yr(e)?Hf(e):KS(e)}o(GS,"getNodeScroll");function E3(e){var t=e.getBoundingClientRect(),n=t.width/e.offsetWidth||1,l=t.height/e.offsetHeight||1;return n!==1||l!==1}o(E3,"isElementScaled");function YS(e,t,n){n===void 0&&(n=!1);var l=Yr(t),d=Yr(t)&&E3(t),h=Bn(t),c=Mo(e,d),v={scrollLeft:0,scrollTop:0},C={x:0,y:0};return(l||!l&&!n)&&((Pn(t)!=="body"||Uf(h))&&(v=GS(t)),Yr(t)?(C=Mo(t,!0),C.x+=t.clientLeft,C.y+=t.clientTop):h&&(C.x=Wf(h))),{x:c.left+v.scrollLeft-C.x,y:c.top+v.scrollTop-C.y,width:c.width,height:c.height}}o(YS,"getCompositeRect");function _3(e){var t=new Map,n=new Set,l=[];e.forEach(function(h){t.set(h.name,h)});function d(h){n.add(h.name);var c=[].concat(h.requires||[],h.requiresIfExists||[]);c.forEach(function(v){if(!n.has(v)){var C=t.get(v);C&&d(C)}}),l.push(h)}return o(d,"sort"),e.forEach(function(h){n.has(h.name)||d(h)}),l}o(_3,"order");function XS(e){var t=_3(e);return KN.reduce(function(n,l){return n.concat(t.filter(function(d){return d.phase===l}))},[])}o(XS,"orderModifiers");function QS(e){var t;return function(){return t||(t=new Promise(function(n){Promise.resolve().then(function(){t=void 0,n(e())})})),t}}o(QS,"debounce");function ZS(e){var t=e.reduce(function(n,l){var d=n[l.name];return n[l.name]=d?Object.assign({},d,l,{options:Object.assign({},d.options,l.options),data:Object.assign({},d.data,l.data)}):l,n},{});return Object.keys(t).map(function(n){return t[n]})}o(ZS,"mergeByName");var aL={placement:"bottom",modifiers:[],strategy:"absolute"};function uL(){for(var e=arguments.length,t=new Array(e),n=0;nxi.default.createElement("li",{role:"separator",className:"divider"}),"Divider");function ii(l){var d=l,{onClick:e,children:t}=d,n=Ws(d,["onClick","children"]);return xi.default.createElement("li",null,xi.default.createElement("a",ke({href:"#",onClick:o(c=>{c.preventDefault(),e()},"click")},n),t))}o(ii,"MenuItem");var cu=xi.default.memo(o(function(v){var C=v,{text:t,children:n,options:l,className:d,onOpen:h}=C,c=Ws(C,["text","children","options","className","onOpen"]);let[k,O]=(0,xi.useState)(null),[j,B]=(0,xi.useState)(!1),[X,J]=(0,xi.useState)(null),{styles:Z,attributes:R}=eC(k,X,ke({},l)),A=o(G=>{B(G),h&&h(G)},"setOpen");(0,xi.useEffect)(()=>{!X||document.addEventListener("click",G=>{X.contains(G.target)?document.addEventListener("click",()=>A(!1),{once:!0}):(G.preventDefault(),G.stopPropagation(),A(!1))},{once:!0,capture:!0})},[X]);let I;return j?I=xi.default.createElement("ul",ke({className:"dropdown-menu show",ref:J,style:Z.popper},R.popper),n):I=null,xi.default.createElement(xi.default.Fragment,null,xi.default.createElement("a",ke({href:"#",ref:O,className:(0,hL.default)(d,{open:j}),onClick:G=>{G.preventDefault(),A(!0)}},c),t),I)},"Dropdown"));function vm({value:e,onChange:t}){let n=qe(d=>d.backendState.contentViews||[]),l=zf.default.createElement("span",null,zf.default.createElement("i",{className:"fa fa-fw fa-files-o"}),"\xA0",zf.default.createElement("b",null,"View:")," ",e.toLowerCase()," ",zf.default.createElement("span",{className:"caret"}));return zf.default.createElement(cu,{text:l,className:"btn btn-default btn-xs",options:{placement:"top-start"}},n.map(d=>zf.default.createElement(ii,{key:d,onClick:()=>t(d)},d.toLowerCase().replace("_"," "))))}o(vm,"ViewSelector");function tC({flow:e,message:t}){let n=Qt(),l=e.request===t?"request":"response",d=qe(J=>J.ui.flow.contentViewFor[e.id+l]||"Auto"),h=(0,tr.useRef)(null),[c,v]=(0,tr.useState)(qe(J=>J.options.content_view_lines_cutoff)),C=(0,tr.useCallback)(()=>v(Math.max(1024,c*2)),[c]),[k,O]=(0,tr.useState)(!1),j;k?j=Kr.getContentURL(e,t):j=Kr.getContentURL(e,t,d,c+1);let B=G0(j,t.contentHash),X=(0,tr.useMemo)(()=>{if(B&&!k)try{return JSON.parse(B)}catch(J){return{description:"Network Error",lines:[[["error",`${B}`]]]}}else return},[B]);if(k)return tr.default.createElement("div",{className:"contentview",key:"edit"},tr.default.createElement("div",{className:"controls"},tr.default.createElement("h5",null,"[Editing]"),tr.default.createElement(kr,{onClick:o(()=>Ia(this,null,function*(){var R;let Z=(R=h.current)==null?void 0:R.getContent();yield n(Wi(e,{[l]:{content:Z}})),O(!1)}),"save"),icon:"fa-check text-success",className:"btn-xs"},"Done"),"\xA0",tr.default.createElement(kr,{onClick:()=>O(!1),icon:"fa-times text-danger",className:"btn-xs"},"Cancel")),tr.default.createElement(fm,{ref:h,initialContent:B||""}));{let J=X?X.description:"Loading...";return tr.default.createElement("div",{className:"contentview",key:"view"},tr.default.createElement("div",{className:"controls"},tr.default.createElement("h5",null,J),tr.default.createElement(kr,{onClick:()=>O(!0),icon:"fa-edit",className:"btn-xs"},"Edit"),"\xA0",tr.default.createElement(Y0,{icon:"fa-upload",text:"Replace",title:"Upload a file to replace the content.",onOpenFile:Z=>n(iN(e,Z,l)),className:"btn btn-default btn-xs"}),"\xA0",tr.default.createElement(vm,{value:d,onChange:Z=>n(x0(e.id+l,Z))})),rC.matches(t)&&tr.default.createElement(rC,{flow:e,message:t}),tr.default.createElement(X0,{lines:(X==null?void 0:X.lines)||[],maxLines:c,showMore:C}))}}o(tC,"HttpMessage");var M3=/^image\/(png|jpe?g|gif|webp|vnc.microsoft.icon|x-icon)$/i;rC.matches=e=>M3.test(Kr.getContentType(e)||"");function rC({flow:e,message:t}){return tr.default.createElement("div",{className:"flowview-image"},tr.default.createElement("img",{src:Kr.getContentURL(e,t),alt:"preview",className:"img-thumbnail"}))}o(rC,"ViewImage");function A3({flow:e}){let t=Qt();return Ut.createElement("div",{className:"first-line request-line"},Ut.createElement("div",null,Ut.createElement(Df,{content:e.request.method,onEditDone:n=>t(Wi(e,{request:{method:n}})),isValid:n=>n.length>0}),"\xA0",Ut.createElement(Df,{content:Oo.pretty_url(e.request),onEditDone:n=>t(Wi(e,{request:ke({path:""},mS(n))})),isValid:n=>{var l;return!!((l=mS(n))==null?void 0:l.host)}}),"\xA0",Ut.createElement(Df,{content:e.request.http_version,onEditDone:n=>t(Wi(e,{request:{http_version:n}})),isValid:gS})))}o(A3,"RequestLine");function D3({flow:e}){let t=Qt();return Ut.createElement("div",{className:"first-line response-line"},Ut.createElement(Df,{content:e.response.http_version,onEditDone:n=>t(Wi(e,{response:{http_version:n}})),isValid:gS}),"\xA0",Ut.createElement(Df,{content:e.response.status_code+"",onEditDone:n=>t(Wi(e,{response:{code:parseInt(n)}})),isValid:n=>/^\d+$/.test(n)}),e.response.http_version!=="HTTP/2.0"&&Ut.createElement(Ut.Fragment,null,"\xA0",Ut.createElement(Xs,{content:e.response.reason,onEditDone:n=>t(Wi(e,{response:{msg:n}}))})))}o(D3,"ResponseLine");function R3({flow:e,message:t}){let n=Qt(),l=e.request===t?"request":"response";return Ut.createElement(Bp,{className:"headers",data:t.headers,onChange:d=>n(Wi(e,{[l]:{headers:d}}))})}o(R3,"Headers");function I3({flow:e,message:t}){let n=Qt(),l=e.request===t?"request":"response";return!Kr.get_first_header(t,/^trailer$/i)?null:Ut.createElement(Ut.Fragment,null,Ut.createElement("hr",null),Ut.createElement("h5",null,"HTTP Trailers"),Ut.createElement(Bp,{className:"trailers",data:t.trailers,onChange:h=>n(Wi(e,{[l]:{trailers:h}}))}))}o(I3,"Trailers");var gL=Ut.memo(o(function({flow:t,message:n}){let l=t.request===n?"request":"response",d=t.request===n?A3:D3;return Ut.createElement("section",{className:l},Ut.createElement(d,{flow:t}),Ut.createElement(R3,{flow:t,message:n}),Ut.createElement("hr",null),Ut.createElement(tC,{key:t.id+l,flow:t,message:n}),Ut.createElement(I3,{flow:t,message:n}))},"Message"));function nC(){let e=qe(t=>t.flows.byId[t.flows.selected[0]]);return Ut.createElement(gL,{flow:e,message:e.request})}o(nC,"Request");nC.displayName="Request";function iC(){let e=qe(t=>t.flows.byId[t.flows.selected[0]]);return Ut.createElement(gL,{flow:e,message:e.response})}o(iC,"Response");iC.displayName="Response";var Ye=fe(Oe());var F3=o(({message:e})=>Ye.createElement("div",null,e.query?e.op_code:e.response_code,"\xA0",e.truncation?"(Truncated)":""),"Summary"),B3=o(({message:e})=>Ye.createElement(Ye.Fragment,null,Ye.createElement("h5",null,e.recursion_desired?"Recursive ":"","Question"),Ye.createElement("table",null,Ye.createElement("thead",null,Ye.createElement("tr",null,Ye.createElement("th",null,"Name"),Ye.createElement("th",null,"Type"),Ye.createElement("th",null,"Class"))),Ye.createElement("tbody",null,e.questions.map((t,n)=>Ye.createElement("tr",{key:n},Ye.createElement("td",null,t.name),Ye.createElement("td",null,t.type),Ye.createElement("td",null,t.class)))))),"Questions"),oC=o(({name:e,values:t})=>Ye.createElement(Ye.Fragment,null,Ye.createElement("h5",null,e),t.length>0?Ye.createElement("table",null,Ye.createElement("thead",null,Ye.createElement("tr",null,Ye.createElement("th",null,"Name"),Ye.createElement("th",null,"Type"),Ye.createElement("th",null,"Class"),Ye.createElement("th",null,"TTL"),Ye.createElement("th",null,"Data"))),Ye.createElement("tbody",null,t.map((n,l)=>Ye.createElement("tr",{key:l},Ye.createElement("td",null,n.name),Ye.createElement("td",null,n.type),Ye.createElement("td",null,n.class),Ye.createElement("td",null,n.ttl),Ye.createElement("td",null,n.data))))):"\u2014"),"ResourceRecords"),vL=o(({type:e,message:t})=>Ye.createElement("section",{className:"dns-"+e},Ye.createElement("div",{className:`first-line ${e}-line`},Ye.createElement(F3,{message:t})),Ye.createElement(B3,{message:t}),Ye.createElement("hr",null),Ye.createElement(oC,{name:`${t.authoritative_answer?"Authoritative ":""}${t.recursion_available?"Recursive ":""}Answer`,values:t.answers}),Ye.createElement("hr",null),Ye.createElement(oC,{name:"Authority",values:t.authorities}),Ye.createElement("hr",null),Ye.createElement(oC,{name:"Additional",values:t.additionals})),"Message");function sC(){let e=qe(t=>t.flows.byId[t.flows.selected[0]]);return Ye.createElement(vL,{type:"request",message:e.request})}o(sC,"Request");sC.displayName="Request";function lC(){let e=qe(t=>t.flows.byId[t.flows.selected[0]]);return Ye.createElement(vL,{type:"response",message:e.response})}o(lC,"Response");lC.displayName="Response";var Ee=fe(Oe());function yL({conn:e}){var n,l,d;let t=null;return"address"in e?t=Ee.createElement(Ee.Fragment,null,Ee.createElement("tr",null,Ee.createElement("td",null,"Address:"),Ee.createElement("td",null,(n=e.address)==null?void 0:n.join(":"))),e.peername&&Ee.createElement("tr",null,Ee.createElement("td",null,"Resolved address:"),Ee.createElement("td",null,e.peername.join(":"))),e.sockname&&Ee.createElement("tr",null,Ee.createElement("td",null,"Source address:"),Ee.createElement("td",null,e.sockname.join(":")))):((l=e.peername)==null?void 0:l[0])&&(t=Ee.createElement(Ee.Fragment,null,Ee.createElement("tr",null,Ee.createElement("td",null,"Address:"),Ee.createElement("td",null,(d=e.peername)==null?void 0:d.join(":"))))),Ee.createElement("table",{className:"connection-table"},Ee.createElement("tbody",null,t,e.sni?Ee.createElement("tr",null,Ee.createElement("td",null,Ee.createElement("abbr",{title:"TLS Server Name Indication"},"SNI"),":"),Ee.createElement("td",null,e.sni)):null,e.alpn?Ee.createElement("tr",null,Ee.createElement("td",null,Ee.createElement("abbr",{title:"ALPN protocol negotiated"},"ALPN"),":"),Ee.createElement("td",null,e.alpn)):null,e.tls_version?Ee.createElement("tr",null,Ee.createElement("td",null,"TLS Version:"),Ee.createElement("td",null,e.tls_version)):null,e.cipher?Ee.createElement("tr",null,Ee.createElement("td",null,"TLS Cipher:"),Ee.createElement("td",null,e.cipher)):null))}o(yL,"ConnectionInfo");function wL(e){return Ee.createElement("dl",{className:"cert-attributes"},e.map(([t,n])=>Ee.createElement(Ee.Fragment,{key:t},Ee.createElement("dt",null,t),Ee.createElement("dd",null,n))))}o(wL,"attrList");function H3({flow:e}){var n;let t=(n=e.server_conn)==null?void 0:n.cert;return t?Ee.createElement(Ee.Fragment,null,Ee.createElement("h4",{key:"name"},"Server Certificate"),Ee.createElement("table",{className:"certificate-table"},Ee.createElement("tbody",null,Ee.createElement("tr",null,Ee.createElement("td",null,"Type"),Ee.createElement("td",null,t.keyinfo[0],", ",t.keyinfo[1]," bits")),Ee.createElement("tr",null,Ee.createElement("td",null,"SHA256 digest"),Ee.createElement("td",null,t.sha256)),Ee.createElement("tr",null,Ee.createElement("td",null,"Valid from"),Ee.createElement("td",null,no(t.notbefore,{milliseconds:!1}))),Ee.createElement("tr",null,Ee.createElement("td",null,"Valid to"),Ee.createElement("td",null,no(t.notafter,{milliseconds:!1}))),Ee.createElement("tr",null,Ee.createElement("td",null,"Subject Alternative Names"),Ee.createElement("td",null,t.altnames.join(", "))),Ee.createElement("tr",null,Ee.createElement("td",null,"Subject"),Ee.createElement("td",null,wL(t.subject))),Ee.createElement("tr",null,Ee.createElement("td",null,"Issuer"),Ee.createElement("td",null,wL(t.issuer))),Ee.createElement("tr",null,Ee.createElement("td",null,"Serial"),Ee.createElement("td",null,t.serial))))):Ee.createElement(Ee.Fragment,null)}o(H3,"CertificateInfo");function ly({flow:e}){var t;return Ee.createElement("section",{className:"detail"},Ee.createElement("h4",null,"Client Connection"),Ee.createElement(yL,{conn:e.client_conn}),((t=e.server_conn)==null?void 0:t.address)&&Ee.createElement(Ee.Fragment,null,Ee.createElement("h4",null,"Server Connection"),Ee.createElement(yL,{conn:e.server_conn})),Ee.createElement(H3,{flow:e}))}o(ly,"Connection");ly.displayName="Connection";var ym=fe(Oe());function ay({flow:e}){return ym.createElement("section",{className:"error"},ym.createElement("div",{className:"alert alert-warning"},e.error.msg,ym.createElement("div",null,ym.createElement("small",null,no(e.error.timestamp)))))}o(ay,"Error");ay.displayName="Error";var fs=fe(Oe());function W3({t:e,deltaTo:t,title:n}){return e?fs.createElement("tr",null,fs.createElement("td",null,n,":"),fs.createElement("td",null,no(e),t&&fs.createElement("span",{className:"text-muted"},"(",C0(1e3*(e-t)),")"))):fs.createElement("tr",null)}o(W3,"TimeStamp");function uy({flow:e}){var l,d,h,c,v,C;let t;e.type==="http"?t=e.request.timestamp_start:t=e.client_conn.timestamp_start;let n=[{title:"Server conn. initiated",t:(l=e.server_conn)==null?void 0:l.timestamp_start,deltaTo:t},{title:"Server conn. TCP handshake",t:(d=e.server_conn)==null?void 0:d.timestamp_tcp_setup,deltaTo:t},{title:"Server conn. TLS handshake",t:(h=e.server_conn)==null?void 0:h.timestamp_tls_setup,deltaTo:t},{title:"Server conn. closed",t:(c=e.server_conn)==null?void 0:c.timestamp_end,deltaTo:t},{title:"Client conn. established",t:e.client_conn.timestamp_start,deltaTo:e.type==="http"?t:void 0},{title:"Client conn. TLS handshake",t:e.client_conn.timestamp_tls_setup,deltaTo:t},{title:"Client conn. closed",t:e.client_conn.timestamp_end,deltaTo:t}];return e.type==="http"&&n.push({title:"First request byte",t:e.request.timestamp_start},{title:"Request complete",t:e.request.timestamp_end,deltaTo:t},{title:"First response byte",t:(v=e.response)==null?void 0:v.timestamp_start,deltaTo:t},{title:"Response complete",t:(C=e.response)==null?void 0:C.timestamp_end,deltaTo:t}),fs.createElement("section",{className:"timing"},fs.createElement("h4",null,"Timing"),fs.createElement("table",{className:"timing-table"},fs.createElement("tbody",null,n.filter(k=>!!k.t).sort((k,O)=>k.t-O.t).map(k=>fs.createElement(W3,ke({key:k.title},k))))))}o(uy,"Timing");uy.displayName="Timing";var pu=fe(Oe());var Zs=fe(Oe()),jp=fe(Oe());function $f({flow:e,messages_meta:t}){let n=Qt(),l=qe(k=>k.ui.flow.contentViewFor[e.id+"messages"]||"Auto"),[d,h]=(0,jp.useState)(qe(k=>k.options.content_view_lines_cutoff)),c=(0,jp.useCallback)(()=>h(Math.max(1024,d*2)),[d]),v=G0(Kr.getContentURL(e,"messages",l,d+1),e.id+t.count),C=(0,jp.useMemo)(()=>{if(v)try{return JSON.parse(v)}catch(k){return[{description:"Network Error",lines:[[["error",`${v}`]]]}]}},[v])||[];return Zs.createElement("div",{className:"contentview"},Zs.createElement("div",{className:"controls"},Zs.createElement("h5",null,t.count," Messages"),Zs.createElement(vm,{value:l,onChange:k=>n(x0(e.id+"messages",k))})),C.map((k,O)=>{let j=`fa fa-fw fa-arrow-${k.from_client?"right text-primary":"left text-danger"}`,B=Zs.createElement("div",{key:O},Zs.createElement("small",null,Zs.createElement("i",{className:j}),Zs.createElement("span",{className:"pull-right"},k.timestamp&&no(k.timestamp))),Zs.createElement(X0,{lines:k.lines,maxLines:d,showMore:c}));return d-=k.lines.length,B}))}o($f,"Messages");function fy({flow:e}){return pu.createElement("section",{className:"websocket"},pu.createElement("h4",null,"WebSocket"),pu.createElement($f,{flow:e,messages_meta:e.websocket.messages_meta}),pu.createElement(U3,{websocket:e.websocket}))}o(fy,"WebSocket");fy.displayName="WebSocket";function U3({websocket:e}){if(!e.timestamp_end)return null;let t=e.close_reason?`(${e.close_reason})`:"";return pu.createElement("div",null,pu.createElement("i",{className:"fa fa-fw fa-window-close text-muted"}),"\xA0 Closed by ",e.closed_by_client?"client":"server"," ","with code ",e.close_code," ",t,".",pu.createElement("small",{className:"pull-right"},no(e.timestamp_end)))}o(U3,"CloseSummary");var xL=fe(ti());var aC=fe(Oe());function cy({flow:e}){return aC.createElement("section",{className:"tcp"},aC.createElement($f,{flow:e,messages_meta:e.messages_meta}))}o(cy,"TcpMessages");cy.displayName="Stream Data";var uC=fe(Oe());function py({flow:e}){return uC.createElement("section",{className:"udp"},uC.createElement($f,{flow:e,messages_meta:e.messages_meta}))}o(py,"UdpMessages");py.displayName="Datagrams";var SL={request:nC,response:iC,error:ay,connection:ly,timing:uy,websocket:fy,tcpmessages:cy,udpmessages:py,dnsrequest:sC,dnsresponse:lC};function dy(e){let t;switch(e.type){case"http":t=["request","response","websocket"].filter(n=>e[n]);break;case"tcp":t=["tcpmessages"];break;case"udp":t=["udpmessages"];break;case"dns":t=["request","response"].filter(n=>e[n]).map(n=>"dns"+n);break}return e.error&&t.push("error"),t.push("connection"),t.push("timing"),t}o(dy,"tabsForFlow");function fC(){let e=Qt(),t=qe(h=>h.flows.byId[h.flows.selected[0]]),n=dy(t),l=qe(h=>h.ui.flow.tab);n.indexOf(l)<0&&(l==="response"&&t.error?l="error":l==="error"&&"response"in t?l="response":l=n[0]);let d=SL[l];return wm.createElement("div",{className:"flow-detail"},wm.createElement("nav",{className:"nav-tabs nav-tabs-sm"},n.map(h=>wm.createElement("a",{key:h,href:"#",className:(0,xL.default)({active:l===h}),onClick:c=>{c.preventDefault(),e(Lf(h))}},SL[h].displayName))),wm.createElement(d,{flow:t}))}o(fC,"FlowView");function CL(e){if(e.ctrlKey||e.metaKey)return()=>{};let t=e.key;return e.preventDefault(),(n,l)=>{let d=l().flows,h=d.byId[l().flows.selected[0]];switch(t){case"k":case"ArrowUp":n(Mf(d,-1));break;case"j":case"ArrowDown":n(Mf(d,1));break;case" ":case"PageDown":n(Mf(d,10));break;case"PageUp":n(Mf(d,-10));break;case"End":n(Mf(d,1e10));break;case"Home":n(Mf(d,-1e10));break;case"Escape":l().ui.modal.activeModal?n($0()):n(Af(void 0));break;case"ArrowLeft":{if(!h)break;let c=dy(h),v=l().ui.flow.tab,C=c[(Math.max(0,c.indexOf(v))-1+c.length)%c.length];n(Lf(C));break}case"Tab":case"ArrowRight":{if(!h)break;let c=dy(h),v=l().ui.flow.tab,C=c[(Math.max(0,c.indexOf(v))+1)%c.length];n(Lf(C));break}case"Delete":case"d":{if(!h)return;n(B0(h));break}case"n":{Pf("view.flows.create","get","https://example.com/");break}case"D":{if(!h)return;n(H0(h));break}case"a":{h&&h.intercepted&&n(Op(h));break}case"A":{n(I0());break}case"r":{h&&n(Mp(h));break}case"v":{h&&h.modified&&n(W0(h));break}case"x":{h&&h.intercepted&&n(F0(h));break}case"X":{n(nN());break}case"z":{n(U0());break}default:return}}}o(CL,"onKeyDown");var Zp=fe(Oe());var xm=fe(Oe()),Sm=fe(iu()),bL=fe(ti()),qp=class extends xm.Component{constructor(t,n){super(t,n);this.state={applied:!1,startX:0,startY:0},this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onDragEnd=this.onDragEnd.bind(this)}onMouseDown(t){this.setState({startX:t.pageX,startY:t.pageY}),window.addEventListener("mousemove",this.onMouseMove),window.addEventListener("mouseup",this.onMouseUp),window.addEventListener("dragend",this.onDragEnd)}onDragEnd(){Sm.default.findDOMNode(this).style.transform="",window.removeEventListener("dragend",this.onDragEnd),window.removeEventListener("mouseup",this.onMouseUp),window.removeEventListener("mousemove",this.onMouseMove)}onMouseUp(t){this.onDragEnd();let n=Sm.default.findDOMNode(this),l=n.previousElementSibling,d=l.offsetHeight+t.pageY-this.state.startY;this.props.axis==="x"&&(d=l.offsetWidth+t.pageX-this.state.startX),l.style.flex=`0 0 ${Math.max(0,d)}px`,n.nextElementSibling.style.flex="1 1 auto",this.setState({applied:!0}),this.onResize()}onMouseMove(t){let n=0,l=0;this.props.axis==="x"?n=t.pageX-this.state.startX:l=t.pageY-this.state.startY,Sm.default.findDOMNode(this).style.transform=`translate(${n}px, ${l}px)`}onResize(){window.setTimeout(()=>window.dispatchEvent(new CustomEvent("resize")),1)}reset(t){if(!this.state.applied)return;let n=Sm.default.findDOMNode(this);n.previousElementSibling&&(n.previousElementSibling.style.flex=""),n.nextElementSibling&&(n.nextElementSibling.style.flex=""),t||this.setState({applied:!1}),this.onResize()}componentWillUnmount(){this.reset(!0)}render(){return xm.default.createElement("div",{className:(0,bL.default)("splitter",this.props.axis==="x"?"splitter-x":"splitter-y")},xm.default.createElement("div",{onMouseDown:this.onMouseDown,draggable:"true"}))}};o(qp,"Splitter"),qp.defaultProps={axis:"x"};var cs=fe(Oe()),Em=fe(Cm()),my=fe(iu());var BL=fe(cC());var pC=fe(iu()),ML=Symbol("shouldStick"),AL=o(e=>Math.round(e.scrollTop)+e.clientHeight===e.scrollHeight,"isAtBottom"),hy=o(e=>{var t;return Object.assign((o(t=class extends e{UNSAFE_componentWillUpdate(){let l=pC.default.findDOMNode(this);this[ML]=l.scrollTop&&AL(l),super.UNSAFE_componentWillUpdate&&super.UNSAFE_componentWillUpdate(),super.componentWillUpdate&&super.componentWillUpdate()}componentDidUpdate(){let l=pC.default.findDOMNode(this);this[ML]&&!AL(l)&&(l.scrollTop=l.scrollHeight),super.componentDidUpdate&&super.componentDidUpdate()}},"AutoScrollWrapper"),t.displayName=e.name,t),e)},"default");function jf(e=void 0){if(!e)return{start:0,end:0,paddingTop:0,paddingBottom:0};let{itemCount:t,rowHeight:n,viewportTop:l,viewportHeight:d,itemHeights:h}=e,c=l+d,v=0,C=0,k=0,O=0;if(h){let j=0;for(let B=0;B0&&jv.flows.sort.desc),l=qe(v=>v.flows.sort.column),d=qe(v=>v.options.web_columns),h=n?"sort-desc":"sort-asc",c=d.map(v=>im[v]).filter(v=>v).concat(Pp);return bm.createElement("tr",null,c.map(v=>bm.createElement("th",{className:(0,DL.default)(`col-${v.name}`,l===v.name&&h),key:v.name,onClick:()=>t(rN(v.name===l&&n?void 0:v.name,v.name!==l?!1:!n))},v.headerName)))},"FlowTableHead"));var Vp=fe(Oe()),IL=fe(ti());var FL=Vp.default.memo(o(function({flow:t,selected:n,highlighted:l}){let d=Qt(),h=qe(k=>k.options.web_columns),c=(0,IL.default)({selected:n,highlighted:l,intercepted:t.intercepted,"has-request":t.type==="http"&&t.request,"has-response":t.type==="http"&&t.response}),v=(0,Vp.useCallback)(k=>{let O=k.target;for(;O.parentNode;){if(O.classList.contains("col-quickactions"))return;O=O.parentNode}d(Af(t.id))},[t]),C=h.map(k=>im[k]).filter(k=>k).concat(Pp);return Vp.default.createElement("tr",{className:c,onClick:v},C.map(k=>Vp.default.createElement(k,{key:k.name,flow:t})))},"FlowRow"));var _m=class extends cs.Component{constructor(t,n){super(t,n);this.state={vScroll:jf()},this.onViewportUpdate=this.onViewportUpdate.bind(this)}UNSAFE_componentWillMount(){window.addEventListener("resize",this.onViewportUpdate)}componentDidMount(){this.onViewportUpdate()}UNSAFE_componentWillUnmount(){window.removeEventListener("resize",this.onViewportUpdate)}componentDidUpdate(){if(this.onViewportUpdate(),!this.shouldScrollIntoView)return;this.shouldScrollIntoView=!1;let{rowHeight:t,flows:n,selected:l}=this.props,d=my.default.findDOMNode(this),h=my.default.findDOMNode(this.refs.head),c=h?h.offsetHeight:0,v=n.indexOf(l)*t+c,C=v+t,k=d.scrollTop,O=d.offsetHeight;v-ck+O&&(d.scrollTop=C-O)}UNSAFE_componentWillReceiveProps(t){t.selected&&t.selected!==this.props.selected&&(this.shouldScrollIntoView=!0)}onViewportUpdate(){let t=my.default.findDOMNode(this),n=t.scrollTop||0,l=jf({viewportTop:n,viewportHeight:t.offsetHeight||0,itemCount:this.props.flows.length,rowHeight:this.props.rowHeight});if(this.state.viewportTop!==n||!(0,BL.default)(this.state.vScroll,l)){let d=Math.min(n,l.end*this.props.rowHeight);this.setState({vScroll:l,viewportTop:d})}}render(){let{vScroll:t,viewportTop:n}=this.state,{flows:l,selected:d,highlight:h}=this.props,c=h?Of.parse(h):()=>!1;return cs.createElement("div",{className:"flow-table",onScroll:this.onViewportUpdate},cs.createElement("table",null,cs.createElement("thead",{ref:"head",style:{transform:`translateY(${n}px)`}},cs.createElement(RL,null)),cs.createElement("tbody",null,cs.createElement("tr",{style:{height:t.paddingTop}}),l.slice(t.start,t.end).map(v=>cs.createElement(FL,{key:v.id,flow:v,selected:v===d,highlighted:c(v)})),cs.createElement("tr",{style:{height:t.paddingBottom}}))))}};o(_m,"FlowTable"),Vc(_m,"propTypes",{flows:Em.default.array.isRequired,rowHeight:Em.default.number,highlight:Em.default.string,selected:Em.default.object}),Vc(_m,"defaultProps",{rowHeight:32});var j3=hy(_m),HL=Hi(e=>({flows:e.flows.view,highlight:e.flows.highlight,selected:e.flows.byId[e.flows.selected[0]]}))(j3);var Nr=fe(Oe()),ky=fe(Oe());var zP=fe(UP());function IC(){let e=qe(n=>n.backendState.servers),t;return e.length===0?t="":e.length===1?t="Configure your client to use the following proxy server:":t="Configure your client to use one of the following proxy servers:",Nr.createElement("div",{style:{padding:"1em 2em"}},Nr.createElement("h3",null,"mitmproxy is running."),Nr.createElement("p",null,"No flows have been recorded yet.",Nr.createElement("br",null),t),Nr.createElement("ul",{className:"fa-ul"},e.map((n,l)=>Nr.createElement("li",{key:n.full_spec},Nr.createElement(HB,ke({},n))))))}o(IC,"CaptureSetup");function HB({description:e,listen_addrs:t,last_exception:n,is_running:l,full_spec:d,wireguard_conf:h}){let c=(0,ky.useRef)(null);(0,ky.useEffect)(()=>{h&&c.current&&zP.default.toCanvas(c.current,h,{margin:0,scale:3})},[h]);let v,C=t.length===1||t.length===2&&t[0][1]===t[1][1],k=t.every(B=>["::","0.0.0.0"].includes(B[0]));C&&k?v=nS(["*",t[0][1]]):v=t.map(nS).join(" and "),e=e[0].toUpperCase()+e.substr(1);let O,j;return n?(j="fa-exclamation text-error",O=Nr.createElement(Nr.Fragment,null,e," (",d,"):",Nr.createElement("br",null),n)):l?(j="fa-check text-success",O=`${e} listening at ${v}.`,h&&(O=Nr.createElement(Nr.Fragment,null,O,Nr.createElement("div",{className:"wireguard-config"},Nr.createElement("pre",null,h),Nr.createElement("canvas",{ref:c}))))):(j="fa-pause text-warning",O=Nr.createElement(Nr.Fragment,null,e," (",d,")")),Nr.createElement(Nr.Fragment,null,Nr.createElement("i",{className:`fa fa-li ${j}`}),O)}o(HB,"ServerDescription");function FC(){let e=qe(n=>!!n.flows.byId[n.flows.selected[0]]),t=qe(n=>n.flows.list.length>0);return Zp.createElement("div",{className:"main-view"},t?Zp.createElement(HL,null):Zp.createElement(IC,null),e&&Zp.createElement(qp,{key:"splitter"}),e&&Zp.createElement(fC,{key:"flowDetails"}))}o(FC,"MainView");var Io=fe(Oe()),YP=fe(ti());var oi=fe(Oe());var ps=fe(Oe()),Ny=fe(iu()),$P=fe(ti());var oo=fe(Oe());var so=class extends oo.Component{constructor(t,n){super(t,n);this.state={doc:so.doc}}componentDidMount(){so.xhr||(so.xhr=kt("/filter-help").then(t=>t.json()),so.xhr.catch(()=>{so.xhr=null})),this.state.doc||so.xhr.then(t=>{so.doc=t,this.setState({doc:t})})}render(){let{doc:t}=this.state;return t?oo.default.createElement("table",{className:"table table-condensed"},oo.default.createElement("tbody",null,t.commands.map(n=>oo.default.createElement("tr",{key:n[1],onClick:l=>this.props.selectHandler(n[0].split(" ")[0]+" ")},oo.default.createElement("td",null,n[0].replace(" ","\xA0")),oo.default.createElement("td",null,n[1]))),oo.default.createElement("tr",{key:"docs-link"},oo.default.createElement("td",{colSpan:2},oo.default.createElement("a",{href:"https://mitmproxy.org/docs/latest/concepts-filters/",target:"_blank"},oo.default.createElement("i",{className:"fa fa-external-link"}),"\xA0 mitmproxy docs"))))):oo.default.createElement("i",{className:"fa fa-spinner fa-spin"})}};o(so,"FilterDocs");var Yf=class extends ps.Component{constructor(t,n){super(t,n);this.state={value:this.props.value,focus:!1,mousefocus:!1},this.onChange=this.onChange.bind(this),this.onFocus=this.onFocus.bind(this),this.onBlur=this.onBlur.bind(this),this.onKeyDown=this.onKeyDown.bind(this),this.onMouseEnter=this.onMouseEnter.bind(this),this.onMouseLeave=this.onMouseLeave.bind(this),this.selectFilter=this.selectFilter.bind(this)}UNSAFE_componentWillReceiveProps(t){this.setState({value:t.value})}isValid(t){try{return t&&Of.parse(t),!0}catch(n){return!1}}getDesc(){if(!this.state.value)return ps.default.createElement(so,{selectHandler:this.selectFilter});try{return Of.parse(this.state.value).desc}catch(t){return""+t}}onChange(t){let n=t.target.value;this.setState({value:n}),this.isValid(n)&&this.props.onChange(n)}onFocus(){this.setState({focus:!0})}onBlur(){this.setState({focus:!1})}onMouseEnter(){this.setState({mousefocus:!0})}onMouseLeave(){this.setState({mousefocus:!1})}onKeyDown(t){(t.key==="Escape"||t.key==="Enter")&&(this.blur(),this.setState({mousefocus:!1})),t.stopPropagation()}selectFilter(t){this.setState({value:t}),Ny.default.findDOMNode(this.refs.input).focus()}blur(){Ny.default.findDOMNode(this.refs.input).blur()}select(){Ny.default.findDOMNode(this.refs.input).select()}render(){let{type:t,color:n,placeholder:l}=this.props,{value:d,focus:h,mousefocus:c}=this.state;return ps.default.createElement("div",{className:(0,$P.default)("filter-input input-group",{"has-error":!this.isValid(d)})},ps.default.createElement("span",{className:"input-group-addon"},ps.default.createElement("i",{className:"fa fa-fw fa-"+t,style:{color:n}})),ps.default.createElement("input",{type:"text",ref:"input",placeholder:l,className:"form-control",value:d,onChange:this.onChange,onFocus:this.onFocus,onBlur:this.onBlur,onKeyDown:this.onKeyDown}),(h||c)&&ps.default.createElement("div",{className:"popover bottom",onMouseEnter:this.onMouseEnter,onMouseLeave:this.onMouseLeave},ps.default.createElement("div",{className:"arrow"}),ps.default.createElement("div",{className:"popover-content"},this.getDesc())))}};o(Yf,"FilterInput");Jp.title="Start";function Jp(){return oi.createElement("div",{className:"main-menu"},oi.createElement("div",{className:"menu-group"},oi.createElement("div",{className:"menu-content"},oi.createElement(UB,null),oi.createElement(zB,null)),oi.createElement("div",{className:"menu-legend"},"Find")),oi.createElement("div",{className:"menu-group"},oi.createElement("div",{className:"menu-content"},oi.createElement(WB,null),oi.createElement($B,null)),oi.createElement("div",{className:"menu-legend"},"Intercept")))}o(Jp,"StartMenu");function WB(){let e=Qt(),t=qe(n=>n.options.intercept);return oi.createElement(Yf,{value:t||"",placeholder:"Intercept",type:"pause",color:"hsl(208, 56%, 53%)",onChange:n=>e(Ip("intercept",n))})}o(WB,"InterceptInput");function UB(){let e=Qt(),t=qe(n=>n.flows.filter);return oi.createElement(Yf,{value:t||"",placeholder:"Search",type:"search",color:"black",onChange:n=>e(D0(n))})}o(UB,"FlowFilterInput");function zB(){let e=Qt(),t=qe(n=>n.flows.highlight);return oi.createElement(Yf,{value:t||"",placeholder:"Highlight",type:"tag",color:"hsl(48, 100%, 50%)",onChange:n=>e(R0(n))})}o(zB,"HighlightInput");function $B(){let e=Qt();return oi.createElement(kr,{className:"btn-sm",title:"[a]ccept all",icon:"fa-forward text-success",onClick:()=>e(I0())},"Resume All")}o($B,"ResumeAll");var Qr=fe(Oe());var Xf=fe(Oe());function BC({value:e,onChange:t,children:n}){return Xf.createElement("div",{className:"menu-entry"},Xf.createElement("label",null,Xf.createElement("input",{type:"checkbox",checked:e,onChange:t}),n))}o(BC,"MenuToggle");function Ly({name:e,children:t}){let n=Qt(),l=qe(d=>d.options[e]);return Xf.createElement(BC,{value:!!l,onChange:()=>n(Ip(e,!l))},t)}o(Ly,"OptionsToggle");function jP(){let e=Gs(),t=qe(n=>n.eventLog.visible);return Xf.createElement(BC,{value:t,onChange:()=>e(Rp())},"Display Event Log")}o(jP,"EventlogToggle");function qP(){let e=Gs(),t=qe(n=>n.commandBar.visible);return Xf.createElement(BC,{value:t,onChange:()=>e(K0())},"Display Command Bar")}o(qP,"CommandBarToggle");var HC=fe(Oe());function WC({children:e,resource:t}){let n=`https://docs.mitmproxy.org/stable/${t}`;return HC.createElement("a",{target:"_blank",href:n},e||HC.createElement("i",{className:"fa fa-question-circle"}))}o(WC,"DocsLink");var Py=fe(Oe());function Ro({children:e}){return window.MITMWEB_STATIC?null:Py.createElement(Py.Fragment,null,e)}o(Ro,"HideInStatic");Oy.title="Options";function Oy(){let e=Qt(),t=o(()=>lN("OptionModal"),"openOptions");return Qr.createElement("div",null,Qr.createElement(Ro,null,Qr.createElement("div",{className:"menu-group"},Qr.createElement("div",{className:"menu-content"},Qr.createElement(kr,{title:"Open Options",icon:"fa-cogs text-primary",onClick:()=>e(t())},"Edit Options ",Qr.createElement("sup",null,"alpha"))),Qr.createElement("div",{className:"menu-legend"},"Options Editor")),Qr.createElement("div",{className:"menu-group"},Qr.createElement("div",{className:"menu-content"},Qr.createElement(Ly,{name:"anticache"},"Strip cache headers"," ",Qr.createElement(WC,{resource:"overview-features/#anticache"})),Qr.createElement(Ly,{name:"showhost"},"Use host header for display"),Qr.createElement(Ly,{name:"ssl_insecure"},"Don't verify server certificates")),Qr.createElement("div",{className:"menu-legend"},"Quick Options"))),Qr.createElement("div",{className:"menu-group"},Qr.createElement("div",{className:"menu-content"},Qr.createElement(jP,null),Qr.createElement(qP,null)),Qr.createElement("div",{className:"menu-legend"},"View Options")))}o(Oy,"OptionMenu");var Hn=fe(Oe());var VP=Hn.memo(o(function(){let t=Gs(),n=qe(l=>l.flows.filter);return Hn.createElement(cu,{className:"pull-left special",text:"File",options:{placement:"bottom-start"}},Hn.createElement("li",null,Hn.createElement(Y0,{icon:"fa-folder-open",text:"\xA0Open...",onClick:l=>l.stopPropagation(),onOpenFile:l=>{t(oN(l)),document.body.click()}})),Hn.createElement(ii,{onClick:()=>location.replace("/flows/dump")},Hn.createElement("i",{className:"fa fa-fw fa-floppy-o"}),"\xA0Save"),Hn.createElement(ii,{onClick:()=>location.replace("/flows/dump?filter="+n)},Hn.createElement("i",{className:"fa fa-fw fa-floppy-o"}),"\xA0Save filtered"),Hn.createElement(ii,{onClick:()=>confirm("Delete all flows?")&&t(U0())},Hn.createElement("i",{className:"fa fa-fw fa-trash"}),"\xA0Clear All"),Hn.createElement(Ro,null,Hn.createElement(mL,null),Hn.createElement("li",null,Hn.createElement("a",{href:"http://mitm.it/",target:"_blank"},Hn.createElement("i",{className:"fa fa-fw fa-external-link"}),"\xA0Install Certificates..."))))},"FileMenu"));var at=fe(Oe());function KP(e){if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(e);{let t=document.createElement("textarea");t.value=e,t.style.position="absolute",t.style.opacity="0",document.body.appendChild(t);try{return t.focus(),t.select(),document.execCommand("copy"),Promise.resolve()}catch(n){return alert(e),Promise.reject(n)}finally{t.remove()}}}o(KP,"copyToClipboard");var ed=o((e,t)=>Ia(void 0,null,function*(){let n=yield Pf("export",t,`@${e.id}`);n.value?yield KP(n.value):n.error?alert(n.error):console.error(n)}),"copy");td.title="Flow";function td(){let e=Qt(),t=qe(n=>n.flows.byId[n.flows.selected[0]]);return t?at.createElement("div",{className:"flow-menu"},at.createElement(Ro,null,at.createElement("div",{className:"menu-group"},at.createElement("div",{className:"menu-content"},at.createElement(kr,{title:"[r]eplay flow",icon:"fa-repeat text-primary",onClick:()=>e(Mp(t)),disabled:!_0(t)},"Replay"),at.createElement(kr,{title:"[D]uplicate flow",icon:"fa-copy text-info",onClick:()=>e(H0(t))},"Duplicate"),at.createElement(kr,{disabled:!t||!t.modified,title:"revert changes to flow [V]",icon:"fa-history text-warning",onClick:()=>e(W0(t))},"Revert"),at.createElement(kr,{title:"[d]elete flow",icon:"fa-trash text-danger",onClick:()=>e(B0(t))},"Delete"),at.createElement(KB,{flow:t})),at.createElement("div",{className:"menu-legend"},"Flow Modification"))),at.createElement("div",{className:"menu-group"},at.createElement("div",{className:"menu-content"},at.createElement(jB,{flow:t}),at.createElement(qB,{flow:t})),at.createElement("div",{className:"menu-legend"},"Export")),at.createElement(Ro,null,at.createElement("div",{className:"menu-group"},at.createElement("div",{className:"menu-content"},at.createElement(kr,{disabled:!t||!t.intercepted,title:"[a]ccept intercepted flow",icon:"fa-play text-success",onClick:()=>e(Op(t))},"Resume"),at.createElement(kr,{disabled:!t||!t.intercepted,title:"kill intercepted flow [x]",icon:"fa-times text-danger",onClick:()=>e(F0(t))},"Abort")),at.createElement("div",{className:"menu-legend"},"Interception")))):at.createElement("div",null)}o(td,"FlowMenu");var My=o(e=>{let t=window.open(e,"_blank","noopener,noreferrer");t&&(t.opener=null)},"openInNewTab");function jB({flow:e}){var t;if(e.type!=="http")return at.createElement(kr,{icon:"fa-download",onClick:()=>0,disabled:!0},"Download");if(e.request.contentLength&&!((t=e.response)==null?void 0:t.contentLength))return at.createElement(kr,{icon:"fa-download",onClick:()=>My(Kr.getContentURL(e,e.request))},"Download");if(e.response){let n=e.response;if(!e.request.contentLength&&e.response.contentLength)return at.createElement(kr,{icon:"fa-download",onClick:()=>My(Kr.getContentURL(e,n))},"Download");if(e.request.contentLength&&e.response.contentLength)return at.createElement(cu,{text:at.createElement(kr,{icon:"fa-download",onClick:()=>1},"Download\u25BE"),options:{placement:"bottom-start"}},at.createElement(ii,{onClick:()=>My(Kr.getContentURL(e,e.request))},"Download request"),at.createElement(ii,{onClick:()=>My(Kr.getContentURL(e,n))},"Download response"))}return null}o(jB,"DownloadButton");function qB({flow:e}){return at.createElement(cu,{className:"",text:at.createElement(kr,{title:"Export flow.",icon:"fa-clone",onClick:()=>1,disabled:e.type!=="http"},"Export\u25BE"),options:{placement:"bottom-start"}},at.createElement(ii,{onClick:()=>ed(e,"raw_request")},"Copy raw request"),at.createElement(ii,{onClick:()=>ed(e,"raw_response")},"Copy raw response"),at.createElement(ii,{onClick:()=>ed(e,"raw")},"Copy raw request and response"),at.createElement(ii,{onClick:()=>ed(e,"curl")},"Copy as cURL"),at.createElement(ii,{onClick:()=>ed(e,"httpie")},"Copy as HTTPie"))}o(qB,"ExportButton");var VB={":red_circle:":"\u{1F534}",":orange_circle:":"\u{1F7E0}",":yellow_circle:":"\u{1F7E1}",":green_circle:":"\u{1F7E2}",":large_blue_circle:":"\u{1F535}",":purple_circle:":"\u{1F7E3}",":brown_circle:":"\u{1F7E4}"};function KB({flow:e}){let t=Qt();return at.createElement(cu,{className:"",text:at.createElement(kr,{title:"mark flow",icon:"fa-paint-brush text-success",onClick:()=>1},"Mark\u25BE"),options:{placement:"bottom-start"}},at.createElement(ii,{onClick:()=>t(Wi(e,{marked:""}))},"\u26AA (no marker)"),Object.entries(VB).map(([n,l])=>at.createElement(ii,{key:n,onClick:()=>t(Wi(e,{marked:n}))},l," ",n.replace(/[:_]/g," "))))}o(KB,"MarkButton");var vu=fe(Oe());var GP=vu.memo(o(function(){let t=qe(l=>l.connection.state),n=qe(l=>l.connection.message);switch(t){case ni.INIT:return vu.createElement("span",{className:"connection-indicator init"},"connecting\u2026");case ni.FETCHING:return vu.createElement("span",{className:"connection-indicator fetching"},"fetching data\u2026");case ni.ESTABLISHED:return vu.createElement("span",{className:"connection-indicator established"},"connected");case ni.ERROR:return vu.createElement("span",{className:"connection-indicator error",title:n},"connection lost");case ni.OFFLINE:return vu.createElement("span",{className:"connection-indicator offline"},"offline");default:let l=t;throw"unknown connection state"}},"ConnectionIndicator"));function UC(){let e=qe(v=>v.flows.selected.filter(C=>C in v.flows.byId)),[t,n]=(0,Io.useState)(()=>Jp),[l,d]=(0,Io.useState)(!1),h=[Jp,Oy];e.length>0?(l||(n(()=>td),d(!0)),h.push(td)):(l&&d(!1),t===td&&n(()=>Jp));function c(v,C){C.preventDefault(),n(()=>v)}return o(c,"handleClick"),Io.default.createElement("header",null,Io.default.createElement("nav",{className:"nav-tabs nav-tabs-lg"},Io.default.createElement(VP,null),h.map(v=>Io.default.createElement("a",{key:v.title,href:"#",className:(0,YP.default)({active:v===t}),onClick:C=>c(v,C)},v.title)),Io.default.createElement(Ro,null,Io.default.createElement(GP,null))),Io.default.createElement("div",null,Io.default.createElement(t,null)))}o(UC,"Header");var Je=fe(Oe()),XP=fe(ti());var Ay=function(){"use strict";function e(l,d){function h(){this.constructor=l}o(h,"ctor"),h.prototype=d.prototype,l.prototype=new h}o(e,"peg$subclass");function t(l,d,h,c){this.message=l,this.expected=d,this.found=h,this.location=c,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,t)}o(t,"peg$SyntaxError"),e(t,Error);function n(l){var d=arguments.length>1?arguments[1]:{},h=this,c={},v={Expr:Cr},C=Cr,k=o(function(H,ee){return[H,...ee]},"peg$c0"),O=o(function(H){return[H]},"peg$c1"),j=o(function(){return""},"peg$c2"),B={type:"other",description:"string"},X='"',J={type:"literal",value:'"',description:'"\\""'},Z=o(function(H){return H.join("")},"peg$c6"),R="'",A={type:"literal",value:"'",description:`"'"`},I=/^["\\]/,G={type:"class",value:'["\\\\]',description:'["\\\\]'},K={type:"any",description:"any character"},se=o(function(H){return H},"peg$c12"),ne="\\",pe={type:"literal",value:"\\",description:'"\\\\"'},me=/^['\\]/,xe={type:"class",value:"['\\\\]",description:"['\\\\]"},Ve=/^['"\\]/,tt={type:"class",value:`['"\\\\]`,description:`['"\\\\]`},_e="n",St={type:"literal",value:"n",description:'"n"'},We=o(function(){return` -`},"peg$c21"),Ke="r",Ge={type:"literal",value:"r",description:'"r"'},Xe=o(function(){return"\r"},"peg$c24"),nr="t",ct={type:"literal",value:"t",description:'"t"'},Hr=o(function(){return" "},"peg$c27"),Zt={type:"other",description:"whitespace"},_t=/^[ \t\n\r]/,Ct={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},ut={type:"other",description:"control character"},Lr=/^[|&!()~"]/,zt={type:"class",value:'[|&!()~"]',description:'[|&!()~"]'},$t={type:"other",description:"optional whitespace"},ie=0,rt=0,Pr=[{line:1,column:1,seenCR:!1}],Gt=0,Yt=[],Se=0,Or;if("startRule"in d){if(!(d.startRule in v))throw new Error(`Can't start parsing from rule "`+d.startRule+'".');C=v[d.startRule]}function fn(){return l.substring(rt,ie)}o(fn,"text");function Un(){return gr(rt,ie)}o(Un,"location");function si(H){throw Ho(null,[{type:"other",description:H}],l.substring(rt,ie),gr(rt,ie))}o(si,"expected");function cn(H){throw Ho(H,null,l.substring(rt,ie),gr(rt,ie))}o(cn,"error");function Jt(H){var ee=Pr[H],he,Te;if(ee)return ee;for(he=H-1;!Pr[he];)he--;for(ee=Pr[he],ee={line:ee.line,column:ee.column,seenCR:ee.seenCR};heGt&&(Gt=ie,Yt=[]),Yt.push(H))}o(pt,"peg$fail");function Ho(H,ee,he,Te){function ir(Ft){var Wr=1;for(Ft.sort(function(or,li){return or.descriptionli.description?1:0});Wr1?li.slice(0,-1).join(", ")+" or "+li[Ft.length-1]:li[0],lo=Wr?'"'+or(Wr)+'"':"end of input","Expected "+ds+" but "+lo+" found."}return o(Ul,"buildMessage"),ee!==null&&ir(ee),new t(H!==null?H:Ul(ee,he),ee,he,Te)}o(Ho,"peg$buildException");function Cr(){var H,ee,he,Te;if(H=ie,ee=Ui(),ee!==c){if(he=[],Te=$n(),Te!==c)for(;Te!==c;)he.push(Te),Te=$n();else he=c;he!==c?(Te=Cr(),Te!==c?(rt=H,ee=k(ee,Te),H=ee):(ie=H,H=c)):(ie=H,H=c)}else ie=H,H=c;if(H===c&&(H=ie,ee=Ui(),ee!==c&&(rt=H,ee=O(ee)),H=ee,H===c)){for(H=ie,ee=[],he=$n();he!==c;)ee.push(he),he=$n();ee!==c&&(rt=H,ee=j()),H=ee}return H}o(Cr,"peg$parseExpr");function Ui(){var H,ee,he,Te;if(Se++,H=ie,l.charCodeAt(ie)===34?(ee=X,ie++):(ee=c,Se===0&&pt(J)),ee!==c){for(he=[],Te=pn();Te!==c;)he.push(Te),Te=pn();he!==c?(l.charCodeAt(ie)===34?(Te=X,ie++):(Te=c,Se===0&&pt(J)),Te!==c?(rt=H,ee=Z(he),H=ee):(ie=H,H=c)):(ie=H,H=c)}else ie=H,H=c;if(H===c){if(H=ie,l.charCodeAt(ie)===39?(ee=R,ie++):(ee=c,Se===0&&pt(A)),ee!==c){for(he=[],Te=zn();Te!==c;)he.push(Te),Te=zn();he!==c?(l.charCodeAt(ie)===39?(Te=R,ie++):(Te=c,Se===0&&pt(A)),Te!==c?(rt=H,ee=Z(he),H=ee):(ie=H,H=c)):(ie=H,H=c)}else ie=H,H=c;if(H===c){if(H=ie,ee=ie,Se++,he=Mn(),Se--,he===c?ee=void 0:(ie=ee,ee=c),ee!==c){if(he=[],Te=Si(),Te!==c)for(;Te!==c;)he.push(Te),Te=Si();else he=c;he!==c?(rt=H,ee=Z(he),H=ee):(ie=H,H=c)}else ie=H,H=c;if(H===c){if(H=ie,l.charCodeAt(ie)===34?(ee=X,ie++):(ee=c,Se===0&&pt(J)),ee!==c){for(he=[],Te=pn();Te!==c;)he.push(Te),Te=pn();he!==c?(rt=H,ee=Z(he),H=ee):(ie=H,H=c)}else ie=H,H=c;if(H===c)if(H=ie,l.charCodeAt(ie)===39?(ee=R,ie++):(ee=c,Se===0&&pt(A)),ee!==c){for(he=[],Te=zn();Te!==c;)he.push(Te),Te=zn();he!==c?(rt=H,ee=Z(he),H=ee):(ie=H,H=c)}else ie=H,H=c}}}return Se--,H===c&&(ee=c,Se===0&&pt(B)),H}o(Ui,"peg$parseStringLiteral");function pn(){var H,ee,he;return H=ie,ee=ie,Se++,I.test(l.charAt(ie))?(he=l.charAt(ie),ie++):(he=c,Se===0&&pt(G)),Se--,he===c?ee=void 0:(ie=ee,ee=c),ee!==c?(l.length>ie?(he=l.charAt(ie),ie++):(he=c,Se===0&&pt(K)),he!==c?(rt=H,ee=se(he),H=ee):(ie=H,H=c)):(ie=H,H=c),H===c&&(H=ie,l.charCodeAt(ie)===92?(ee=ne,ie++):(ee=c,Se===0&&pt(pe)),ee!==c?(he=Ci(),he!==c?(rt=H,ee=se(he),H=ee):(ie=H,H=c)):(ie=H,H=c)),H}o(pn,"peg$parseDoubleStringChar");function zn(){var H,ee,he;return H=ie,ee=ie,Se++,me.test(l.charAt(ie))?(he=l.charAt(ie),ie++):(he=c,Se===0&&pt(xe)),Se--,he===c?ee=void 0:(ie=ee,ee=c),ee!==c?(l.length>ie?(he=l.charAt(ie),ie++):(he=c,Se===0&&pt(K)),he!==c?(rt=H,ee=se(he),H=ee):(ie=H,H=c)):(ie=H,H=c),H===c&&(H=ie,l.charCodeAt(ie)===92?(ee=ne,ie++):(ee=c,Se===0&&pt(pe)),ee!==c?(he=Ci(),he!==c?(rt=H,ee=se(he),H=ee):(ie=H,H=c)):(ie=H,H=c)),H}o(zn,"peg$parseSingleStringChar");function Si(){var H,ee,he;return H=ie,ee=ie,Se++,he=$n(),Se--,he===c?ee=void 0:(ie=ee,ee=c),ee!==c?(l.length>ie?(he=l.charAt(ie),ie++):(he=c,Se===0&&pt(K)),he!==c?(rt=H,ee=se(he),H=ee):(ie=H,H=c)):(ie=H,H=c),H}o(Si,"peg$parseUnquotedStringChar");function Ci(){var H,ee;return Ve.test(l.charAt(ie))?(H=l.charAt(ie),ie++):(H=c,Se===0&&pt(tt)),H===c&&(H=ie,l.charCodeAt(ie)===110?(ee=_e,ie++):(ee=c,Se===0&&pt(St)),ee!==c&&(rt=H,ee=We()),H=ee,H===c&&(H=ie,l.charCodeAt(ie)===114?(ee=Ke,ie++):(ee=c,Se===0&&pt(Ge)),ee!==c&&(rt=H,ee=Xe()),H=ee,H===c&&(H=ie,l.charCodeAt(ie)===116?(ee=nr,ie++):(ee=c,Se===0&&pt(ct)),ee!==c&&(rt=H,ee=Hr()),H=ee))),H}o(Ci,"peg$parseEscapeSequence");function $n(){var H,ee;return Se++,_t.test(l.charAt(ie))?(H=l.charAt(ie),ie++):(H=c,Se===0&&pt(Ct)),Se--,H===c&&(ee=c,Se===0&&pt(Zt)),H}o($n,"peg$parsews");function Mn(){var H,ee;return Se++,Lr.test(l.charAt(ie))?(H=l.charAt(ie),ie++):(H=c,Se===0&&pt(zt)),Se--,H===c&&(ee=c,Se===0&&pt(ut)),H}o(Mn,"peg$parsecc");function Js(){var H,ee;for(Se++,H=[],ee=$n();ee!==c;)H.push(ee),ee=$n();return Se--,H===c&&(ee=c,Se===0&&pt($t)),H}if(o(Js,"peg$parse__"),Or=C(),Or!==c&&ie===l.length)return Or;throw Or!==c&&ie{t&&t.current.addEventListener("DOMNodeInserted",n=>{let l=n.currentTarget;l.scroll({top:l.scrollHeight,behavior:"auto"})})},[]),Je.default.createElement("div",{className:"command-result",ref:t},e.map((n,l)=>Je.default.createElement("div",{key:l},Je.default.createElement("div",null,Je.default.createElement("strong",null,"$ ",n.command)),n.result)))}o(GB,"Results");function YB({nextArgs:e,currentArg:t,help:n,description:l,availableCommands:d}){let h=[];for(let c=0;c0&&Je.default.createElement("div",null,Je.default.createElement("strong",null,"Argument suggestion:")," ",h),(n==null?void 0:n.includes("->"))&&Je.default.createElement("div",null,Je.default.createElement("strong",null,"Signature help: "),n),l&&Je.default.createElement("div",null,"# ",l),Je.default.createElement("div",null,Je.default.createElement("strong",null,"Available Commands: "),Je.default.createElement("p",{className:"available-commands"},JSON.stringify(d)))))}o(YB,"CommandHelp");function $C(){let[e,t]=(0,Je.useState)(""),[n,l]=(0,Je.useState)(""),[d,h]=(0,Je.useState)(0),[c,v]=(0,Je.useState)([]),[C,k]=(0,Je.useState)([]),[O,j]=(0,Je.useState)({}),[B,X]=(0,Je.useState)([]),[J,Z]=(0,Je.useState)(0),[R,A]=(0,Je.useState)(""),[I,G]=(0,Je.useState)(""),[K,se]=(0,Je.useState)([]),[ne,pe]=(0,Je.useState)([]),[me,xe]=(0,Je.useState)(void 0);(0,Je.useEffect)(()=>{kt("/commands",{method:"GET"}).then(We=>We.json()).then(We=>{j(We),v(zC(We)),k(Object.keys(We))}).catch(We=>console.error(We))},[]),(0,Je.useEffect)(()=>{Pf("commands.history.get").then(We=>{pe(We.value)}).catch(We=>console.error(We))},[]);let Ve=o((We,Ke)=>{var ct,Hr,Zt;let Ge=Ay.parse(Ke),Xe=Ay.parse(We);A((ct=O[Ge[0]])==null?void 0:ct.signature_help),G(((Hr=O[Ge[0]])==null?void 0:Hr.help)||""),v(zC(O,Xe[0])),k(zC(O,Ge[0]));let nr=(Zt=O[Ge[0]])==null?void 0:Zt.parameters.map(_t=>_t.name);nr&&(X([Ge[0],...nr]),Z(Ge.length-1))},"parseCommand"),tt=o(We=>{t(We.target.value),l(We.target.value),h(0)},"onChange"),_e=o(We=>{if(We.key==="Enter"){let[Ke,...Ge]=Ay.parse(e);pe([...ne,e]),Pf("commands.history.add",e).catch(()=>0),kt.post(`/commands/${Ke}`,{arguments:Ge}).then(Xe=>Xe.json()).then(Xe=>{xe(void 0),X([]),se([...K,{command:e,result:JSON.stringify(Xe.value||Xe.error)}])}).catch(Xe=>{xe(void 0),X([]),se([...K,{command:e,result:Xe.toString()}])}),A(""),G(""),t(""),l(""),h(0),v(C)}if(We.key==="ArrowUp"){let Ke;me===void 0?Ke=ne.length-1:Ke=Math.max(0,me-1),t(ne[Ke]),l(ne[Ke]),xe(Ke)}if(We.key==="ArrowDown"){if(me===void 0)return;if(me==ne.length-1)t(""),l(""),xe(void 0);else{let Ke=me+1;t(ne[Ke]),l(ne[Ke]),xe(Ke)}}We.key==="Tab"&&(t(c[d]),h((d+1)%c.length),We.preventDefault()),We.stopPropagation()},"onKeyDown"),St=o(We=>{if(!e){k(Object.keys(O));return}Ve(n,e),We.stopPropagation()},"onKeyUp");return Je.default.createElement("div",{className:"command"},Je.default.createElement("div",{className:"command-title"},"Command Result"),Je.default.createElement(GB,{results:K}),Je.default.createElement(YB,{nextArgs:B,currentArg:J,help:R,description:I,availableCommands:C}),Je.default.createElement("div",{className:(0,XP.default)("command-input input-group")},Je.default.createElement("span",{className:"input-group-addon"},Je.default.createElement("i",{className:"fa fa-fw fa-terminal"})),Je.default.createElement("input",{type:"text",placeholder:"Enter command",className:"form-control",value:e||"",onChange:tt,onKeyDown:_e,onKeyUp:St})))}o($C,"CommandBar");var Wl=fe(Oe()),rd=fe(Cm());var jC=fe(Oe());function qC({checked:e,onToggle:t,text:n}){return jC.default.createElement("div",{className:"btn btn-toggle "+(e?"btn-primary":"btn-default"),onClick:t},jC.default.createElement("i",{className:"fa fa-fw "+(e?"fa-check-square-o":"fa-square-o")}),"\xA0",n)}o(qC,"ToggleButton");var Hl=fe(Oe()),VC=fe(Cm()),QP=fe(iu()),ZP=fe(cC());var Dm=class extends Hl.Component{constructor(t){super(t);this.heights={},this.state={vScroll:jf()},this.onViewportUpdate=this.onViewportUpdate.bind(this)}componentDidMount(){window.addEventListener("resize",this.onViewportUpdate),this.onViewportUpdate()}componentWillUnmount(){window.removeEventListener("resize",this.onViewportUpdate)}componentDidUpdate(){this.onViewportUpdate()}onViewportUpdate(){let t=QP.default.findDOMNode(this),n=jf({itemCount:this.props.events.length,rowHeight:this.props.rowHeight,viewportTop:t.scrollTop,viewportHeight:t.offsetHeight,itemHeights:this.props.events.map(l=>this.heights[l.id])});(0,ZP.default)(this.state.vScroll,n)||this.setState({vScroll:n})}setHeight(t,n){if(n&&!this.heights[t]){let l=n.offsetHeight;this.heights[t]!==l&&(this.heights[t]=l,this.onViewportUpdate())}}render(){let{vScroll:t}=this.state,{events:n}=this.props;return Hl.default.createElement("pre",{onScroll:this.onViewportUpdate},Hl.default.createElement("div",{style:{height:t.paddingTop}}),n.slice(t.start,t.end).map(l=>Hl.default.createElement("div",{key:l.id,ref:d=>this.setHeight(l.id,d)},Hl.default.createElement(XB,{event:l}),l.message)),Hl.default.createElement("div",{style:{height:t.paddingBottom}}))}};o(Dm,"EventLogList"),Dm.propTypes={events:VC.default.array.isRequired,rowHeight:VC.default.number},Dm.defaultProps={rowHeight:18};function XB({event:e}){let t={web:"html5",debug:"bug",warn:"exclamation-triangle",error:"ban"}[e.level]||"info";return Hl.default.createElement("i",{className:`fa fa-fw fa-${t}`})}o(XB,"LogIcon");var JP=hy(Dm);var Rm=class extends Wl.Component{constructor(t,n){super(t,n);this.state={height:this.props.defaultHeight},this.onDragStart=this.onDragStart.bind(this),this.onDragMove=this.onDragMove.bind(this),this.onDragStop=this.onDragStop.bind(this)}onDragStart(t){t.preventDefault(),this.dragStart=this.state.height+t.pageY,window.addEventListener("mousemove",this.onDragMove),window.addEventListener("mouseup",this.onDragStop),window.addEventListener("dragend",this.onDragStop)}onDragMove(t){t.preventDefault(),this.setState({height:this.dragStart-t.pageY})}onDragStop(t){t.preventDefault(),window.removeEventListener("mousemove",this.onDragMove)}render(){let{height:t}=this.state,{filters:n,events:l,toggleFilter:d,close:h}=this.props;return Wl.default.createElement("div",{className:"eventlog",style:{height:t}},Wl.default.createElement("div",{onMouseDown:this.onDragStart},"Eventlog",Wl.default.createElement("div",{className:"pull-right"},["debug","info","web","warn","error"].map(c=>Wl.default.createElement(qC,{key:c,text:c,checked:n[c],onToggle:()=>d(c)})),Wl.default.createElement("i",{onClick:h,className:"fa fa-close"}))),Wl.default.createElement(JP,{events:l}))}};o(Rm,"PureEventLog"),Vc(Rm,"propTypes",{filters:rd.default.object.isRequired,events:rd.default.array.isRequired,toggleFilter:rd.default.func.isRequired,close:rd.default.func.isRequired,defaultHeight:rd.default.number}),Vc(Rm,"defaultProps",{defaultHeight:200});var eO=Hi(e=>({filters:e.eventLog.filters,events:e.eventLog.view}),{close:Rp,toggleFilter:vN})(Rm);var un=fe(Oe());function KC(){let e=qe(A=>A.backendState.version),{mode:t,intercept:n,showhost:l,upstream_cert:d,rawtcp:h,http2:c,websocket:v,anticache:C,anticomp:k,stickyauth:O,stickycookie:j,stream_large_bodies:B,listen_host:X,listen_port:J,server:Z,ssl_insecure:R}=qe(A=>A.options);return un.createElement("footer",null,t&&(t.length!==1||t[0]!=="regular")&&un.createElement("span",{className:"label label-success"},t.join(",")),n&&un.createElement("span",{className:"label label-success"},"Intercept: ",n),R&&un.createElement("span",{className:"label label-danger"},"ssl_insecure"),l&&un.createElement("span",{className:"label label-success"},"showhost"),!d&&un.createElement("span",{className:"label label-success"},"no-upstream-cert"),!h&&un.createElement("span",{className:"label label-success"},"no-raw-tcp"),!c&&un.createElement("span",{className:"label label-success"},"no-http2"),!v&&un.createElement("span",{className:"label label-success"},"no-websocket"),C&&un.createElement("span",{className:"label label-success"},"anticache"),k&&un.createElement("span",{className:"label label-success"},"anticomp"),O&&un.createElement("span",{className:"label label-success"},"stickyauth: ",O),j&&un.createElement("span",{className:"label label-success"},"stickycookie: ",j),B&&un.createElement("span",{className:"label label-success"},"stream: ",S0(B)),un.createElement("div",{className:"pull-right"},un.createElement(Ro,null,Z&&un.createElement("span",{className:"label label-primary",title:"HTTP Proxy Server Address"},X||"*",":",J||8080)),un.createElement("span",{className:"label label-default",title:"Mitmproxy Version"},"mitmproxy ",e)))}o(KC,"Footer");var eb=fe(Oe());var JC=fe(Oe());var nd=fe(Oe());function GC({children:e}){return nd.createElement("div",null,nd.createElement("div",{className:"modal-backdrop fade in"}),nd.createElement("div",{className:"modal modal-visible",id:"optionsModal",tabIndex:-1,role:"dialog","aria-labelledby":"options"},nd.createElement("div",{className:"modal-dialog modal-lg",role:"document"},nd.createElement("div",{className:"modal-content"},e))))}o(GC,"ModalLayout");var mr=fe(Oe());var Fo=fe(Oe()),Bo=fe(Cm());var tO=fe(ti()),QB=o(e=>{e.key!=="Escape"&&e.stopPropagation()},"stopPropagation");YC.propTypes={value:Bo.default.bool.isRequired,onChange:Bo.default.func.isRequired};function YC(l){var d=l,{value:e,onChange:t}=d,n=Ws(d,["value","onChange"]);return Fo.default.createElement("div",{className:"checkbox"},Fo.default.createElement("label",null,Fo.default.createElement("input",ke({type:"checkbox",checked:e,onChange:h=>t(h.target.checked)},n)),"Enable"))}o(YC,"BooleanOption");XC.propTypes={value:Bo.default.string,onChange:Bo.default.func.isRequired};function XC(l){var d=l,{value:e,onChange:t}=d,n=Ws(d,["value","onChange"]);return Fo.default.createElement("input",ke({type:"text",value:e||"",onChange:h=>t(h.target.value)},n))}o(XC,"StringOption");function rO(e){return function(l){var d=l,{onChange:t}=d,n=Ws(d,["onChange"]);return Fo.default.createElement(e,ke({onChange:h=>t(h||null)},n))}}o(rO,"Optional");QC.propTypes={value:Bo.default.number.isRequired,onChange:Bo.default.func.isRequired};function QC(l){var d=l,{value:e,onChange:t}=d,n=Ws(d,["value","onChange"]);return Fo.default.createElement("input",ke({type:"number",value:e,onChange:h=>t(parseInt(h.target.value))},n))}o(QC,"NumberOption");nO.propTypes={value:Bo.default.string.isRequired,onChange:Bo.default.func.isRequired};function nO(d){var h=d,{value:e,onChange:t,choices:n}=h,l=Ws(h,["value","onChange","choices"]);return Fo.default.createElement("select",ke({onChange:c=>t(c.target.value),value:e},l),n.map(c=>Fo.default.createElement("option",{key:c,value:c},c)))}o(nO,"ChoicesOption");iO.propTypes={value:Bo.default.arrayOf(Bo.default.string).isRequired,onChange:Bo.default.func.isRequired};function iO(l){var d=l,{value:e,onChange:t}=d,n=Ws(d,["value","onChange"]);let h=Math.max(e.length,1);return Fo.default.createElement("textarea",ke({rows:h,value:e.join(` -`),onChange:c=>t(c.target.value.split(` -`))},n))}o(iO,"StringSequenceOption");var ZB={bool:YC,str:XC,int:QC,"optional str":rO(XC),"optional int":rO(QC),"sequence of str":iO};function JB({choices:e,type:t,value:n,onChange:l,name:d,error:h}){let c,v={};if(e)c=nO,v.choices=e;else if(c=ZB[t],!c)throw`unknown option type ${t}`;return c!==YC&&(v.className="form-control"),Fo.default.createElement("div",{className:(0,tO.default)({"has-error":h})},Fo.default.createElement(c,ke({name:d,value:n,onChange:l,onKeyDown:QB},v)))}o(JB,"PureOption");var oO=Hi((e,{name:t})=>ke(ke({},e.options_meta[t]),e.ui.optionsEditor[t]),(e,{name:t})=>({onChange:n=>e(Ip(t,n))}))(JB);var Dy=fe(Qh());function eH({help:e}){return mr.default.createElement("div",{className:"help-block small"},e)}o(eH,"PureOptionHelp");var tH=Hi((e,{name:t})=>({help:e.options_meta[t].help}))(eH);function rH({error:e}){return e?mr.default.createElement("div",{className:"small text-danger"},e):null}o(rH,"PureOptionError");var nH=Hi((e,{name:t})=>({error:e.ui.optionsEditor[t]&&e.ui.optionsEditor[t].error}))(rH);function iH({value:e,defaultVal:t}){if(e===t)return null;if(typeof t=="boolean")t=t?"true":"false";else if(Array.isArray(t)){if(Dy.default.isEmpty(Dy.default.compact(e))&&Dy.default.isEmpty(t))return null;t="[ ]"}else t===""?t='""':t===null&&(t="null");return mr.default.createElement("div",{className:"small"},"Default: ",mr.default.createElement("strong",null," ",t," ")," ")}o(iH,"PureOptionDefault");var oH=Hi((e,{name:t})=>({value:e.options[t],defaultVal:e.options_meta[t].default}))(iH),ZC=class extends mr.Component{constructor(t,n){super(t,n);this.state={title:"Options"}}componentWillUnmount(){}render(){let{hideModal:t,options:n}=this.props,{title:l}=this.state;return mr.default.createElement("div",null,mr.default.createElement("div",{className:"modal-header"},mr.default.createElement("button",{type:"button",className:"close","data-dismiss":"modal",onClick:()=>{t()}},mr.default.createElement("i",{className:"fa fa-fw fa-times"})),mr.default.createElement("div",{className:"modal-title"},mr.default.createElement("h4",null,l))),mr.default.createElement("div",{className:"modal-body"},mr.default.createElement("div",{className:"form-horizontal"},n.map(d=>mr.default.createElement("div",{key:d,className:"form-group"},mr.default.createElement("div",{className:"col-xs-6"},mr.default.createElement("label",{htmlFor:d},d),mr.default.createElement(tH,{name:d})),mr.default.createElement("div",{className:"col-xs-6"},mr.default.createElement(oO,{name:d}),mr.default.createElement(nH,{name:d}),mr.default.createElement(oH,{name:d})))))),mr.default.createElement("div",{className:"modal-footer"}))}};o(ZC,"PureOptionModal");var sO=Hi(e=>({options:Object.keys(e.options_meta).sort()}),{hideModal:$0,save:PN})(ZC);function sH(){return JC.createElement(GC,null,JC.createElement(sO,null))}o(sH,"OptionModal");var lO=[sH];function tb(){let e=qe(n=>n.ui.modal.activeModal),t=lO.find(n=>n.name===e);return e&&t!==void 0?eb.createElement(t,null):eb.createElement("div",null)}o(tb,"PureModal");var rb=class extends Wn.Component{constructor(){super(...arguments);this.state={};this.render=o(()=>{var l;let{showEventLog:t,showCommandBar:n}=this.props;return this.state.error?(console.log("ERR",this.state),Wn.default.createElement("div",{className:"container"},Wn.default.createElement("h1",null,"mitmproxy has crashed."),Wn.default.createElement("pre",null,this.state.error.stack,Wn.default.createElement("br",null),Wn.default.createElement("br",null),"Component Stack:",(l=this.state.errorInfo)==null?void 0:l.componentStack),Wn.default.createElement("p",null,"Please lodge a bug report at"," ",Wn.default.createElement("a",{href:"https://github.com/mitmproxy/mitmproxy/issues"},"https://github.com/mitmproxy/mitmproxy/issues"),"."))):Wn.default.createElement("div",{id:"container",tabIndex:0},Wn.default.createElement(UC,null),Wn.default.createElement(FC,null),n&&Wn.default.createElement($C,{key:"commandbar"}),t&&Wn.default.createElement(eO,{key:"eventlog"}),Wn.default.createElement(KC,null),Wn.default.createElement(tb,null))},"render")}componentDidMount(){window.addEventListener("keydown",this.props.onKeyDown)}componentWillUnmount(){window.removeEventListener("keydown",this.props.onKeyDown)}componentDidCatch(t,n){this.setState({error:t,errorInfo:n})}};o(rb,"ProxyAppMain");var aO=Hi(e=>({showEventLog:e.eventLog.visible,showCommandBar:e.commandBar.visible}),{onKeyDown:CL})(rb);var yu={SEARCH:"s",HIGHLIGHT:"h",SHOW_EVENTLOG:"e",SHOW_COMMANDBAR:"c"};function lH(e){let[t,n]=window.location.hash.substr(1).split("?",2),l=t.substr(1).split("/");if(l[0]==="flows"&&l.length==3){let[d,h]=l.slice(1);e.dispatch(Af(d)),e.dispatch(Lf(h))}n&&n.split("&").forEach(d=>{let[h,c]=d.split("=",2);switch(c=decodeURIComponent(c),h){case yu.SEARCH:e.dispatch(D0(c));break;case yu.HIGHLIGHT:e.dispatch(R0(c));break;case yu.SHOW_EVENTLOG:e.getState().eventLog.visible||e.dispatch(Rp());break;case yu.SHOW_COMMANDBAR:e.getState().commandBar.visible||e.dispatch(K0());break;default:console.error(`unimplemented query arg: ${d}`)}})}o(lH,"updateStoreFromUrl");function aH(e){let t=e.getState(),n={[yu.SEARCH]:t.flows.filter,[yu.HIGHLIGHT]:t.flows.highlight,[yu.SHOW_EVENTLOG]:t.eventLog.visible,[yu.SHOW_COMMANDBAR]:t.commandBar.visible},l=Object.keys(n).filter(c=>n[c]).map(c=>`${c}=${encodeURIComponent(n[c])}`).join("&"),d;t.flows.selected.length>0?d=`/flows/${t.flows.selected[0]}/${t.ui.flow.tab}`:d="/flows",l&&(d+="?"+l);let h=window.location.pathname;h==="blank"&&(h="/"),window.location.hash.substr(1)!==d&&history.replaceState(void 0,"",`${h}#${d}`)}o(aH,"updateUrlFromStore");function nb(e){lH(e),e.subscribe(()=>aH(e))}o(nb,"initialize");var uH="reset",Im=class{constructor(t){this.activeFetches={},this.store=t,this.connect()}connect(){this.socket=new WebSocket(location.origin.replace("http","ws")+location.pathname.replace(/\/$/,"")+"/updates"),this.socket.addEventListener("open",()=>this.onOpen()),this.socket.addEventListener("close",t=>this.onClose(t)),this.socket.addEventListener("message",t=>this.onMessage(JSON.parse(t.data))),this.socket.addEventListener("error",t=>this.onError(t))}onOpen(){this.fetchData("state"),this.fetchData("flows"),this.fetchData("events"),this.fetchData("options"),this.store.dispatch(TN())}fetchData(t){let n=[];this.activeFetches[t]=n,kt(`./${t}`).then(l=>l.json()).then(l=>{this.activeFetches[t]===n&&this.receive(t,l)})}onMessage(t){if(t.cmd===uH)return this.fetchData(t.resource);if(t.resource in this.activeFetches)this.activeFetches[t.resource].push(t);else{let n=`${t.resource}_${t.cmd}`.toUpperCase();this.store.dispatch(ke({type:n},t))}}receive(t,n){let l=`${t}_RECEIVE`.toUpperCase();this.store.dispatch({type:l,cmd:"receive",resource:t,data:n});let d=this.activeFetches[t];delete this.activeFetches[t],d.forEach(h=>this.onMessage(h)),Object.keys(this.activeFetches).length===0&&this.store.dispatch(kN())}onClose(t){this.store.dispatch(NN(`Connection closed at ${new Date().toUTCString()} with error code ${t.code}.`)),console.error("websocket connection closed",t)}onError(t){console.error("websocket connection errored",arguments)}};o(Im,"WebsocketBackend");var Fm=class{constructor(t){this.store=t,this.onOpen()}onOpen(){this.fetchData("flows"),this.fetchData("options")}fetchData(t){kt(`./${t}`).then(n=>n.json()).then(n=>{this.receive(t,n)})}receive(t,n){let l=`${t}_RECEIVE`.toUpperCase();this.store.dispatch({type:l,cmd:"receive",resource:t,data:n})}};o(Fm,"StaticBackend");nb(Fp);window.MITMWEB_STATIC?window.backend=new Fm(Fp):window.backend=new Im(Fp);window.addEventListener("error",e=>{Fp.dispatch(yN(`${e.message} -${e.error.stack}`))});document.addEventListener("DOMContentLoaded",()=>{(0,uO.render)(ib.createElement(Wx,{store:Fp},ib.createElement(aO,null)),document.getElementById("mitmproxy"))});})(); -/* -object-assign -(c) Sindre Sorhus -@license MIT -*/ -/*! - Copyright (c) 2018 Jed Watson. - Licensed under the MIT License (MIT), see - http://jedwatson.github.io/classnames +`),st}Ry(()=>{Gt.current=void 0,Wt.current=void 0,fn.current=Ue});let Kr=Tt.useMemo(()=>Tt.createElement(ne,{...Ue,ref:Re}),[Re,ne,Ue]);return Tt.useMemo(()=>q?Tt.createElement(Ye.Provider,{value:cn},Kr):Kr,[Ye,Kr,cn])}i(j,"ConnectFunction");let Z=Tt.memo(j);if(Z.WrappedComponent=ne,Z.displayName=j.displayName=L,S){let he=Tt.forwardRef(i(function(Ee,Ye){return Tt.createElement(Z,{...Ee,reactReduxForwardedRef:Ye})},"forwardConnectRef"));return he.displayName=L,he.WrappedComponent=ne,xx(he,ne)}return xx(Z,ne)},"wrapWithConnect")}i(Q4,"connect");var Wu=Q4;function J4({store:e,context:t,children:n,serverState:s,stabilityCheck:l="once",identityFunctionCheck:h="once"}){let d=Tt.useMemo(()=>{let b=xA(e);return{store:e,subscription:b,getServerState:s?()=>s:void 0,stabilityCheck:l,identityFunctionCheck:h}},[e,s,l,h]),v=Tt.useMemo(()=>e.getState(),[e]);Ry(()=>{let{subscription:b}=d;return b.onStateChange=b.notifyNestedSubs,b.trySubscribe(),v!==e.getState()&&b.notifyNestedSubs(),()=>{b.tryUnsubscribe(),b.onStateChange=void 0}},[d,v]);let S=t||gl;return Tt.createElement(S.Provider,{value:d},n)}i(J4,"Provider");var EA=J4;function bA(e=gl){let t=e===gl?gA:Cx(e),n=i(()=>{let{store:s}=t();return s},"useStore2");return Object.assign(n,{withTypes:i(()=>n,"withTypes")}),n}i(bA,"createStoreHook");var Z4=bA();function eB(e=gl){let t=e===gl?Z4:bA(e),n=i(()=>t().dispatch,"useDispatch2");return Object.assign(n,{withTypes:i(()=>n,"withTypes")}),n}i(eB,"createDispatchHook");var TA=eB();a4(hA.useSyncExternalStoreWithSelector);q4(pA.useSyncExternalStore);var Jn=pe(Te());var kA="UI_FLOWVIEW_SET_TAB",NA="SET_CONTENT_VIEW_FOR",tB={tab:"request",contentViewFor:{}};function bx(e=tB,t){switch(t.type){case NA:return{...e,contentViewFor:{...e.contentViewFor,[t.messageId]:t.contentView}};case kA:return{...e,tab:t.tab?t.tab:"request"};default:return e}}i(bx,"reducer");function mf(e){return{type:kA,tab:e}}i(mf,"selectTab");function Dy(e,t){return{type:NA,messageId:e,contentView:t}}i(Dy,"setContentViewFor");var rB=pe(bm()),nB=pe(Te());window.React=nB;var Iy=i(function(e){if(e===0)return"0";let t=["b","kb","mb","gb","tb"],n=0;for(;ne);n++);let s;return e%Math.pow(1024,n)===0?s=0:s=1,(e/Math.pow(1024,n)).toFixed(s)+t[n]},"formatSize"),Fy=i(function(e){let t=e,n=["ms","s","min","h"],s=[1e3,60,60],l=0;for(;Math.abs(t)>=s[l]&&lxt(e,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),...n});xt.post=(e,t,n={})=>xt(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),...n});async function gf(e,...t){return await(await xt(`/commands/${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({arguments:t})})).json()}i(gf,"runCommand");async function AA(e){try{await navigator.clipboard.write([new ClipboardItem({"text/plain":e})]);return}catch(s){console.warn(s)}let t=await e;try{await navigator.clipboard.writeText(t);return}catch(s){console.warn(s)}let n=document.createElement("textarea");n.value=t,n.style.position="absolute",n.style.opacity="0",document.body.appendChild(n);try{if(n.focus(),n.select(),!document.execCommand("copy"))throw"failed to copy"}catch{alert(t)}finally{n.remove()}}i(AA,"copyToClipboard");function Tm(e,t){let n=e.lastIndexOf(t);if(n===-1)return["",e];let s=e.slice(0,n),l=e.slice(n+t.length);return[s,l]}i(Tm,"rpartition");function By(e,t){let n=e.indexOf(t);if(n===-1)return[e,""];let s=e.slice(0,n),l=e.slice(n+t.length);return[s,l]}i(By,"partition");var Am={};xb(Am,{ADD:()=>Ox,RECEIVE:()=>Ix,REMOVE:()=>Dx,SET_FILTER:()=>Lx,SET_SORT:()=>Mx,UPDATE:()=>Rx,add:()=>sB,defaultState:()=>ap,receive:()=>uB,reduce:()=>$u,remove:()=>lB,setFilter:()=>km,setSort:()=>Fx,update:()=>aB});var Px=pe(PA());var Lx="LIST_SET_FILTER",Mx="LIST_SET_SORT",Ox="LIST_ADD",Rx="LIST_UPDATE",Dx="LIST_REMOVE",Ix="LIST_RECEIVE",ap={byId:{},list:[],listIndex:{},view:[],viewIndex:{}};function $u(e=ap,t){let{byId:n,list:s,listIndex:l,view:h,viewIndex:d}=e;switch(t.type){case Lx:h=(0,Px.default)(s.filter(t.filter),t.sort),d={},h.forEach((v,S)=>{d[v.id]=S});break;case Mx:h=(0,Px.default)([...h],t.sort),d={},h.forEach((v,S)=>{d[v.id]=S});break;case Ox:if(t.item.id in n)break;n={...n,[t.item.id]:t.item},l={...l,[t.item.id]:s.length},s=[...s,t.item],t.filter(t.item)&&({view:h,viewIndex:d}=LA(e,t.item,t.sort));break;case Rx:{n={...n,[t.item.id]:t.item},s=[...s],s[l[t.item.id]]=t.item;let v=t.item.id in d,S=t.filter(t.item);S&&!v?{view:h,viewIndex:d}=LA(e,t.item,t.sort):!S&&v?{data:h,dataIndex:d}=Ax(h,d,t.item.id):S&&v&&({view:h,viewIndex:d}=cB(e,t.item,t.sort));break}case Dx:if(!(t.id in n))break;n={...n},delete n[t.id],{data:s,dataIndex:l}=Ax(s,l,t.id),t.id in d&&({data:h,dataIndex:d}=Ax(h,d,t.id));break;case Ix:s=t.list,l={},n={},s.forEach((v,S)=>{n[v.id]=v,l[v.id]=S}),h=s.filter(t.filter).sort(t.sort),d={},h.forEach((v,S)=>{d[v.id]=S});break}return{byId:n,list:s,listIndex:l,view:h,viewIndex:d}}i($u,"reduce");function km(e=Hy,t=Nm){return{type:Lx,filter:e,sort:t}}i(km,"setFilter");function Fx(e=Nm){return{type:Mx,sort:e}}i(Fx,"setSort");function sB(e,t=Hy,n=Nm){return{type:Ox,item:e,filter:t,sort:n}}i(sB,"add");function aB(e,t=Hy,n=Nm){return{type:Rx,item:e,filter:t,sort:n}}i(aB,"update");function lB(e){return{type:Dx,id:e}}i(lB,"remove");function uB(e,t=Hy,n=Nm){return{type:Ix,list:e,filter:t,sort:n}}i(uB,"receive");function LA(e,t,n){let s=fB(e.view,t,n),l=[...e.view],h={...e.viewIndex};l.splice(s,0,t);for(let d=l.length-1;d>=s;d--)h[l[d].id]=d;return{view:l,viewIndex:h}}i(LA,"sortedInsert");function Ax(e,t,n){let s=t[n],l=[...e],h={...t};delete h[n],l.splice(s,1);for(let d=l.length-1;d>=s;d--)h[l[d].id]=d;return{data:l,dataIndex:h}}i(Ax,"removeData");function cB(e,t,n){let s=[...e.view],l={...e.viewIndex},h=l[t.id];for(s[h]=t;h+10;)s[h]=s[h+1],s[h+1]=t,l[t.id]=h+1,l[s[h].id]=h,++h;for(;h>0&&n(s[h],s[h-1])<0;)s[h]=s[h-1],s[h-1]=t,l[t.id]=h-1,l[s[h].id]=h,--h;return{view:s,viewIndex:l}}i(cB,"sortedUpdate");function fB(e,t,n){let s=0,l=e.length;for(;s>>1;n(t,e[h])>=0?s=h+1:l=h}return s}i(fB,"sortedIndex");function Hy(){return!0}i(Hy,"defaultFilter");function Nm(e,t){return 0}i(Nm,"defaultSort");var MA={http:80,https:443},On=class e{static{i(this,"MessageUtils")}static getContentType(t){let n=e.get_first_header(t,/^Content-Type$/i);if(n)return n.split(";")[0].trim()}static get_first_header(t,n){let s=t;s._headerLookups||Object.defineProperty(s,"_headerLookups",{value:{},configurable:!1,enumerable:!1,writable:!1});let l=n.toString();if(!(l in s._headerLookups)){let h;for(let d=0;d{switch(e.type){case"http":{let t=e.request.contentLength||0;return e.response&&(t+=e.response.contentLength||0),e.websocket&&(t+=e.websocket.messages_meta.contentLength||0),t}case"tcp":case"udp":return e.messages_meta.contentLength||0;case"dns":return e.response?.size??0}},"getTotalSize"),zy=i(e=>e.type==="http"&&!e.websocket,"canReplay"),Wx=i(e=>{if(e.type!=="http")return e.client_conn.tls_version==="QUICv1"?"resource-icon-quic":`resource-icon-${e.type}`;if(e.websocket)return"resource-icon-websocket";if(!e.response)return"resource-icon-plain";let t=vl.getContentType(e.response)||"";return e.response.status_code===304?"resource-icon-not-modified":300<=e.response.status_code&&e.response.status_code<400?"resource-icon-redirect":t.indexOf("image")>=0?"resource-icon-image":t.indexOf("javascript")>=0?"resource-icon-js":t.indexOf("css")>=0?"resource-icon-css":t.indexOf("html")>=0?"resource-icon-document":"resource-icon-plain"},"getIcon"),$x=i(e=>{switch(e.type){case"http":return Bs.pretty_url(e.request);case"tcp":case"udp":return`${e.client_conn.peername.join(":")} \u2194 ${e.server_conn?.address?.join(":")}`;case"dns":return`${e.request.questions.map(t=>`${t.name} ${t.type}`).join(", ")} = ${(e.response?.answers.map(t=>t.data).join(", ")??"...")||"?"}`}},"mainPath"),Vx=i(e=>{switch(e.type){case"http":return e.response?.status_code;case"dns":return e.response?.response_code;default:return}},"statusCode"),qx=i(e=>{switch(e.type){case"http":return e.websocket?e.client_conn.tls_established?"WSS":"WS":e.request.method;case"dns":return e.request.op_code;default:return e.type.toUpperCase()}},"getMethod"),jx=i(e=>{switch(e.type){case"http":return e.request.http_version;default:return""}},"getVersion"),OA={tls:i(e=>e.type==="http"&&e.request.scheme,"tls"),icon:Wx,index:i(()=>0,"index"),path:$x,method:qx,version:jx,status:Vx,size:Ux,time:i(e=>{let t=Pm(e),n=zx(e);return t&&n&&n-t},"time"),timestamp:Pm,quickactions:i(()=>0,"quickactions"),comment:i(e=>e.comment,"comment")};var vf=function(){"use strict";function e(s,l){function h(){this.constructor=s}i(h,"ctor"),h.prototype=l.prototype,s.prototype=new h}i(e,"peg$subclass");function t(s,l,h,d){this.message=s,this.expected=l,this.found=h,this.location=d,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,t)}i(t,"peg$SyntaxError"),e(t,Error);function n(s){var l=arguments.length>1?arguments[1]:{},h=this,d={},v={start:vi},S=vi,b={type:"other",description:"filter expression"},k=i(function(w){return w},"peg$c1"),R={type:"other",description:"whitespace"},I=/^[ \t\n\r]/,z={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},q={type:"other",description:"control character"},Q=/^[|&!()~"]/,ne={type:"class",value:'[|&!()~"]',description:'[|&!()~"]'},D={type:"other",description:"optional whitespace"},L="|",B={type:"literal",value:"|",description:'"|"'},j=i(function(w,N){return Sc(w,N)},"peg$c11"),re="&",Z={type:"literal",value:"&",description:'"&"'},oe=i(function(w,N){return Qf(w,N)},"peg$c14"),he="!",Re={type:"literal",value:"!",description:'"!"'},Ee=i(function(w){return Qs(w)},"peg$c17"),Ye="(",tt={type:"literal",value:"(",description:'"("'},xe=")",Xe={type:"literal",value:")",description:'")"'},je=i(function(w){return Js(w)},"peg$c22"),Qe="~all",ot={type:"literal",value:"~all",description:'"~all"'},It=i(function(){return Jf},"peg$c25"),At="~a",cn={type:"literal",value:"~a",description:'"~a"'},fn=i(function(){return xc},"peg$c28"),gr="~b",Wt={type:"literal",value:"~b",description:'"~b"'},vr=i(function(w){return Wo(w)},"peg$c31"),yr="~bq",Gt={type:"literal",value:"~bq",description:'"~bq"'},Ft=i(function(w){return Kt(w)},"peg$c34"),se="~bs",Ue={type:"literal",value:"~bs",description:'"~bs"'},Kr=i(function(w){return Gp(w)},"peg$c37"),Zt="~c",st={type:"literal",value:"~c",description:'"~c"'},Fe=i(function(w){return Cc(w)},"peg$c40"),Fn="~comment",En={type:"literal",value:"~comment",description:'"~comment"'},no=i(function(w){return Zs(w)},"peg$c43"),Ho="~d",lt={type:"literal",value:"~d",description:'"~d"'},wr=i(function(w){return _c(w)},"peg$c46"),fr="~dns",pt={type:"literal",value:"~dns",description:'"~dns"'},io=i(function(){return Ha},"peg$c49"),Bn="~dst",Mi={type:"literal",value:"~dst",description:'"~dst"'},Gr=i(function(w){return ed(w)},"peg$c52"),Yr="~e",oo={type:"literal",value:"~e",description:'"~e"'},hi=i(function(){return Wl},"peg$c55"),Hn="~h",so={type:"literal",value:"~h",description:'"~h"'},bl=i(function(w){return $l(w)},"peg$c58"),Y="~hq",ee={type:"literal",value:"~hq",description:'"~hq"'},Ce=i(function(w){return Ec(w)},"peg$c61"),Me="~hs",Tl={type:"literal",value:"~hs",description:'"~hs"'},ze=i(function(w){return Yp(w)},"peg$c64"),Xr="~http",Yt={type:"literal",value:"~http",description:'"~http"'},Mt=i(function(){return Vl},"peg$c67"),Pt="~marked",Na={type:"literal",value:"~marked",description:'"~marked"'},dn=i(function(){return hn},"peg$c70"),zn="~marker",kr={type:"literal",value:"~marker",description:'"~marker"'},gs=i(function(w){return bc(w)},"peg$c73"),bn="~m",Aa={type:"literal",value:"~m",description:'"~m"'},Pa=i(function(w){return co(w)},"peg$c76"),nc="~q",ic={type:"literal",value:"~q",description:'"~q"'},oc=i(function(){return yi},"peg$c79"),$f="~replayq",sc={type:"literal",value:"~replayq",description:'"~replayq"'},Fp=i(function(){return ea},"peg$c82"),kl="~replays",Bp={type:"literal",value:"~replays",description:'"~replays"'},Hp=i(function(){return ql},"peg$c85"),Nl="~replay",Vf={type:"literal",value:"~replay",description:'"~replay"'},ac=i(function(){return Tc},"peg$c88"),vs="~src",zp={type:"literal",value:"~src",description:'"~src"'},Up=i(function(w){return Fi(w)},"peg$c91"),La="~s",lc={type:"literal",value:"~s",description:'"~s"'},ao=i(function(){return $o},"peg$c94"),qf="~tcp",Oi={type:"literal",value:"~tcp",description:'"~tcp"'},uc=i(function(){return jl},"peg$c97"),cc="~udp",or={type:"literal",value:"~udp",description:'"~udp"'},Pe=i(function(){return xs},"peg$c100"),lo="~tq",Al={type:"literal",value:"~tq",description:'"~tq"'},Ri=i(function(w){return td(w)},"peg$c103"),vt="~ts",ys={type:"literal",value:"~ts",description:'"~ts"'},Ma=i(function(w){return Xp(w)},"peg$c106"),Oa="~t",ce={type:"literal",value:"~t",description:'"~t"'},Ve=i(function(w){return Kl(w)},"peg$c109"),qs="~u",fc={type:"literal",value:"~u",description:'"~u"'},js=i(function(w){return Gl(w)},"peg$c112"),zo="~websocket",dc={type:"literal",value:"~websocket",description:'"~websocket"'},qe=i(function(){return Tn},"peg$c115"),jf={type:"other",description:"integer"},Pl=/^['"]/,ws={type:"class",value:`['"]`,description:`['"]`},mi=/^[0-9]/,Ll={type:"class",value:"[0-9]",description:"[0-9]"},Ml=i(function(w){return parseInt(w.join(""),10)},"peg$c121"),Ss={type:"other",description:"string"},uo='"',Ol={type:"literal",value:'"',description:'"\\""'},Ks=i(function(w){return w.join("")},"peg$c125"),pc="'",Rl={type:"literal",value:"'",description:`"'"`},hc=/^["\\]/,mc={type:"class",value:'["\\\\]',description:'["\\\\]'},Dl={type:"any",description:"any character"},Ra=i(function(w){return w},"peg$c131"),gc="\\",Di={type:"literal",value:"\\",description:'"\\\\"'},Kf=/^['\\]/,Wp={type:"class",value:"['\\\\]",description:"['\\\\]"},Il=/^['"\\]/,Da={type:"class",value:`['"\\\\]`,description:`['"\\\\]`},$p="n",vc={type:"literal",value:"n",description:'"n"'},Vp=i(function(){return` +`},"peg$c140"),qp="r",yc={type:"literal",value:"r",description:'"r"'},Gf=i(function(){return"\r"},"peg$c143"),jp="t",Bt={type:"literal",value:"t",description:'"t"'},Ot=i(function(){return" "},"peg$c146"),M=0,De=0,Gs=[{line:1,column:1,seenCR:!1}],gi=0,Fl=[],ve=0,Ia;if("startRule"in l){if(!(l.startRule in v))throw new Error(`Can't start parsing from rule "`+l.startRule+'".');S=v[l.startRule]}function Kp(){return s.substring(De,M)}i(Kp,"text");function Rt(){return Uo(De,M)}i(Rt,"location");function Yf(w){throw Xs(null,[{type:"other",description:w}],s.substring(De,M),Uo(De,M))}i(Yf,"expected");function Ys(w){throw Xs(w,null,s.substring(De,M),Uo(De,M))}i(Ys,"error");function Fa(w){var N=Gs[w],U,W;if(N)return N;for(U=w-1;!Gs[U];)U--;for(N=Gs[U],N={line:N.line,column:N.column,seenCR:N.seenCR};Ugi&&(gi=M,Fl=[]),Fl.push(w))}i(Se,"peg$fail");function Xs(w,N,U,W){function mn(Un){var fo=1;for(Un.sort(function(Vo,qo){return Vo.descriptionqo.description?1:0});fo1?qo.slice(0,-1).join(", ")+" or "+qo[Un.length-1]:qo[0],Yl=fo?'"'+Vo(fo)+'"':"end of input","Expected "+kc+" but "+Yl+" found."}return i(Xt,"buildMessage"),N!==null&&mn(N),new t(w!==null?w:Xt(N,U),N,U,W)}i(Xs,"peg$buildException");function vi(){var w,N,U,W;return ve++,w=M,N=pn(),N!==d?(U=Hl(),U!==d?(W=pn(),W!==d?(De=w,N=k(U),w=N):(M=w,w=d)):(M=w,w=d)):(M=w,w=d),ve--,w===d&&(N=d,ve===0&&Se(b)),w}i(vi,"peg$parsestart");function Ze(){var w,N;return ve++,I.test(s.charAt(M))?(w=s.charAt(M),M++):(w=d,ve===0&&Se(z)),ve--,w===d&&(N=d,ve===0&&Se(R)),w}i(Ze,"peg$parsews");function Bl(){var w,N;return ve++,Q.test(s.charAt(M))?(w=s.charAt(M),M++):(w=d,ve===0&&Se(ne)),ve--,w===d&&(N=d,ve===0&&Se(q)),w}i(Bl,"peg$parsecc");function pn(){var w,N;for(ve++,w=[],N=Ze();N!==d;)w.push(N),N=Ze();return ve--,w===d&&(N=d,ve===0&&Se(D)),w}i(pn,"peg$parse__");function Hl(){var w,N,U,W,mn,Xt;return w=M,N=Qr(),N!==d?(U=pn(),U!==d?(s.charCodeAt(M)===124?(W=L,M++):(W=d,ve===0&&Se(B)),W!==d?(mn=pn(),mn!==d?(Xt=Hl(),Xt!==d?(De=w,N=j(N,Xt),w=N):(M=w,w=d)):(M=w,w=d)):(M=w,w=d)):(M=w,w=d)):(M=w,w=d),w===d&&(w=Qr()),w}i(Hl,"peg$parseOrExpr");function Qr(){var w,N,U,W,mn,Xt;if(w=M,N=zl(),N!==d?(U=pn(),U!==d?(s.charCodeAt(M)===38?(W=re,M++):(W=d,ve===0&&Se(Z)),W!==d?(mn=pn(),mn!==d?(Xt=Qr(),Xt!==d?(De=w,N=oe(N,Xt),w=N):(M=w,w=d)):(M=w,w=d)):(M=w,w=d)):(M=w,w=d)):(M=w,w=d),w===d){if(w=M,N=zl(),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=Qr(),W!==d?(De=w,N=oe(N,W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;w===d&&(w=zl())}return w}i(Qr,"peg$parseAndExpr");function zl(){var w,N,U,W;return w=M,s.charCodeAt(M)===33?(N=he,M++):(N=d,ve===0&&Se(Re)),N!==d?(U=pn(),U!==d?(W=zl(),W!==d?(De=w,N=Ee(W),w=N):(M=w,w=d)):(M=w,w=d)):(M=w,w=d),w===d&&(w=Zn()),w}i(zl,"peg$parseNotExpr");function Zn(){var w,N,U,W,mn,Xt;return w=M,s.charCodeAt(M)===40?(N=Ye,M++):(N=d,ve===0&&Se(tt)),N!==d?(U=pn(),U!==d?(W=Hl(),W!==d?(mn=pn(),mn!==d?(s.charCodeAt(M)===41?(Xt=xe,M++):(Xt=d,ve===0&&Se(Xe)),Xt!==d?(De=w,N=je(W),w=N):(M=w,w=d)):(M=w,w=d)):(M=w,w=d)):(M=w,w=d)):(M=w,w=d),w===d&&(w=Xf()),w}i(Zn,"peg$parseBindingExpr");function Xf(){var w,N,U,W;if(w=M,s.substr(M,4)===Qe?(N=Qe,M+=4):(N=d,ve===0&&Se(ot)),N!==d&&(De=w,N=It()),w=N,w===d&&(w=M,s.substr(M,2)===At?(N=At,M+=2):(N=d,ve===0&&Se(cn)),N!==d&&(De=w,N=fn()),w=N,w===d)){if(w=M,s.substr(M,2)===gr?(N=gr,M+=2):(N=d,ve===0&&Se(Wt)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=vr(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,3)===yr?(N=yr,M+=3):(N=d,ve===0&&Se(Gt)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Ft(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,3)===se?(N=se,M+=3):(N=d,ve===0&&Se(Ue)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Kr(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,2)===Zt?(N=Zt,M+=2):(N=d,ve===0&&Se(st)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=wc(),W!==d?(De=w,N=Fe(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,8)===Fn?(N=Fn,M+=8):(N=d,ve===0&&Se(En)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=no(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,2)===Ho?(N=Ho,M+=2):(N=d,ve===0&&Se(lt)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=wr(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d&&(w=M,s.substr(M,4)===fr?(N=fr,M+=4):(N=d,ve===0&&Se(pt)),N!==d&&(De=w,N=io()),w=N,w===d)){if(w=M,s.substr(M,4)===Bn?(N=Bn,M+=4):(N=d,ve===0&&Se(Mi)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Gr(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d&&(w=M,s.substr(M,2)===Yr?(N=Yr,M+=2):(N=d,ve===0&&Se(oo)),N!==d&&(De=w,N=hi()),w=N,w===d)){if(w=M,s.substr(M,2)===Hn?(N=Hn,M+=2):(N=d,ve===0&&Se(so)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=bl(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,3)===Y?(N=Y,M+=3):(N=d,ve===0&&Se(ee)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Ce(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,3)===Me?(N=Me,M+=3):(N=d,ve===0&&Se(Tl)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=ze(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d&&(w=M,s.substr(M,5)===Xr?(N=Xr,M+=5):(N=d,ve===0&&Se(Yt)),N!==d&&(De=w,N=Mt()),w=N,w===d&&(w=M,s.substr(M,7)===Pt?(N=Pt,M+=7):(N=d,ve===0&&Se(Na)),N!==d&&(De=w,N=dn()),w=N,w===d))){if(w=M,s.substr(M,7)===zn?(N=zn,M+=7):(N=d,ve===0&&Se(kr)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=gs(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,2)===bn?(N=bn,M+=2):(N=d,ve===0&&Se(Aa)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Pa(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d&&(w=M,s.substr(M,2)===nc?(N=nc,M+=2):(N=d,ve===0&&Se(ic)),N!==d&&(De=w,N=oc()),w=N,w===d&&(w=M,s.substr(M,8)===$f?(N=$f,M+=8):(N=d,ve===0&&Se(sc)),N!==d&&(De=w,N=Fp()),w=N,w===d&&(w=M,s.substr(M,8)===kl?(N=kl,M+=8):(N=d,ve===0&&Se(Bp)),N!==d&&(De=w,N=Hp()),w=N,w===d&&(w=M,s.substr(M,7)===Nl?(N=Nl,M+=7):(N=d,ve===0&&Se(Vf)),N!==d&&(De=w,N=ac()),w=N,w===d))))){if(w=M,s.substr(M,4)===vs?(N=vs,M+=4):(N=d,ve===0&&Se(zp)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Up(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d&&(w=M,s.substr(M,2)===La?(N=La,M+=2):(N=d,ve===0&&Se(lc)),N!==d&&(De=w,N=ao()),w=N,w===d&&(w=M,s.substr(M,4)===qf?(N=qf,M+=4):(N=d,ve===0&&Se(Oi)),N!==d&&(De=w,N=uc()),w=N,w===d&&(w=M,s.substr(M,4)===cc?(N=cc,M+=4):(N=d,ve===0&&Se(or)),N!==d&&(De=w,N=Pe()),w=N,w===d)))){if(w=M,s.substr(M,3)===lo?(N=lo,M+=3):(N=d,ve===0&&Se(Al)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Ri(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,3)===vt?(N=vt,M+=3):(N=d,ve===0&&Se(ys)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Ma(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,2)===Oa?(N=Oa,M+=2):(N=d,ve===0&&Se(ce)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=Ve(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.substr(M,2)===qs?(N=qs,M+=2):(N=d,ve===0&&Se(fc)),N!==d){if(U=[],W=Ze(),W!==d)for(;W!==d;)U.push(W),W=Ze();else U=d;U!==d?(W=jt(),W!==d?(De=w,N=js(W),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;w===d&&(w=M,s.substr(M,10)===zo?(N=zo,M+=10):(N=d,ve===0&&Se(dc)),N!==d&&(De=w,N=qe()),w=N,w===d&&(w=M,N=jt(),N!==d&&(De=w,N=js(N)),w=N))}}}}}}}}}}}}}}}}}return w}i(Xf,"peg$parseExpr");function wc(){var w,N,U,W;if(ve++,w=M,Pl.test(s.charAt(M))?(N=s.charAt(M),M++):(N=d,ve===0&&Se(ws)),N===d&&(N=null),N!==d){if(U=[],mi.test(s.charAt(M))?(W=s.charAt(M),M++):(W=d,ve===0&&Se(Ll)),W!==d)for(;W!==d;)U.push(W),mi.test(s.charAt(M))?(W=s.charAt(M),M++):(W=d,ve===0&&Se(Ll));else U=d;U!==d?(Pl.test(s.charAt(M))?(W=s.charAt(M),M++):(W=d,ve===0&&Se(ws)),W===d&&(W=null),W!==d?(De=w,N=Ml(U),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;return ve--,w===d&&(N=d,ve===0&&Se(jf)),w}i(wc,"peg$parseIntegerLiteral");function jt(){var w,N,U,W;if(ve++,w=M,s.charCodeAt(M)===34?(N=uo,M++):(N=d,ve===0&&Se(Ol)),N!==d){for(U=[],W=Ba();W!==d;)U.push(W),W=Ba();U!==d?(s.charCodeAt(M)===34?(W=uo,M++):(W=d,ve===0&&Se(Ol)),W!==d?(De=w,N=Ks(U),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d){if(w=M,s.charCodeAt(M)===39?(N=pc,M++):(N=d,ve===0&&Se(Rl)),N!==d){for(U=[],W=Ul();W!==d;)U.push(W),W=Ul();U!==d?(s.charCodeAt(M)===39?(W=pc,M++):(W=d,ve===0&&Se(Rl)),W!==d?(De=w,N=Ks(U),w=N):(M=w,w=d)):(M=w,w=d)}else M=w,w=d;if(w===d)if(w=M,N=M,ve++,U=Bl(),ve--,U===d?N=void 0:(M=N,N=d),N!==d){if(U=[],W=$t(),W!==d)for(;W!==d;)U.push(W),W=$t();else U=d;U!==d?(De=w,N=Ks(U),w=N):(M=w,w=d)}else M=w,w=d}return ve--,w===d&&(N=d,ve===0&&Se(Ss)),w}i(jt,"peg$parseStringLiteral");function Ba(){var w,N,U;return w=M,N=M,ve++,hc.test(s.charAt(M))?(U=s.charAt(M),M++):(U=d,ve===0&&Se(mc)),ve--,U===d?N=void 0:(M=N,N=d),N!==d?(s.length>M?(U=s.charAt(M),M++):(U=d,ve===0&&Se(Dl)),U!==d?(De=w,N=Ra(U),w=N):(M=w,w=d)):(M=w,w=d),w===d&&(w=M,s.charCodeAt(M)===92?(N=gc,M++):(N=d,ve===0&&Se(Di)),N!==d?(U=Ii(),U!==d?(De=w,N=Ra(U),w=N):(M=w,w=d)):(M=w,w=d)),w}i(Ba,"peg$parseDoubleStringChar");function Ul(){var w,N,U;return w=M,N=M,ve++,Kf.test(s.charAt(M))?(U=s.charAt(M),M++):(U=d,ve===0&&Se(Wp)),ve--,U===d?N=void 0:(M=N,N=d),N!==d?(s.length>M?(U=s.charAt(M),M++):(U=d,ve===0&&Se(Dl)),U!==d?(De=w,N=Ra(U),w=N):(M=w,w=d)):(M=w,w=d),w===d&&(w=M,s.charCodeAt(M)===92?(N=gc,M++):(N=d,ve===0&&Se(Di)),N!==d?(U=Ii(),U!==d?(De=w,N=Ra(U),w=N):(M=w,w=d)):(M=w,w=d)),w}i(Ul,"peg$parseSingleStringChar");function $t(){var w,N,U;return w=M,N=M,ve++,U=Ze(),ve--,U===d?N=void 0:(M=N,N=d),N!==d?(s.length>M?(U=s.charAt(M),M++):(U=d,ve===0&&Se(Dl)),U!==d?(De=w,N=Ra(U),w=N):(M=w,w=d)):(M=w,w=d),w}i($t,"peg$parseUnquotedStringChar");function Ii(){var w,N;return Il.test(s.charAt(M))?(w=s.charAt(M),M++):(w=d,ve===0&&Se(Da)),w===d&&(w=M,s.charCodeAt(M)===110?(N=$p,M++):(N=d,ve===0&&Se(vc)),N!==d&&(De=w,N=Vp()),w=N,w===d&&(w=M,s.charCodeAt(M)===114?(N=qp,M++):(N=d,ve===0&&Se(yc)),N!==d&&(De=w,N=Gf()),w=N,w===d&&(w=M,s.charCodeAt(M)===116?(N=jp,M++):(N=d,ve===0&&Se(Bt)),N!==d&&(De=w,N=Ot()),w=N))),w}i(Ii,"peg$parseEscapeSequence");function Sc(w,N){function U(){return w.apply(this,arguments)||N.apply(this,arguments)}return i(U,"orFilter"),U.desc=w.desc+" or "+N.desc,U}i(Sc,"or");function Qf(w,N){function U(){return w.apply(this,arguments)&&N.apply(this,arguments)}return i(U,"andFilter"),U.desc=w.desc+" and "+N.desc,U}i(Qf,"and");function Qs(w){function N(){return!w.apply(this,arguments)}return i(N,"notFilter"),N.desc="not "+w.desc,N}i(Qs,"not");function Js(w){function N(){return w.apply(this,arguments)}return i(N,"bindingFilter"),N.desc="("+w.desc+")",N}i(Js,"binding");function Jf(w){return!0}i(Jf,"allFilter"),Jf.desc="all flows";var Zf=[new RegExp("text/javascript"),new RegExp("application/x-javascript"),new RegExp("application/javascript"),new RegExp("text/css"),new RegExp("image/.*"),new RegExp("font/.*"),new RegExp("application/font.*")];function xc(w){if(w.response){for(var N=vl.getContentType(w.response),U=Zf.length;U--;)if(Zf[U].test(N))return!0}return!1}i(xc,"assetFilter"),xc.desc="is asset";function Wo(w){w=new RegExp(w,"i");function N(U){return!0}return i(N,"bodyFilter"),N.desc="body filters are not implemented yet, see https://github.com/mitmproxy/mitmproxy/issues/3609",N}i(Wo,"body");function Kt(w){w=new RegExp(w,"i");function N(U){return!0}return i(N,"requestBodyFilter"),N.desc="body filters are not implemented yet, see https://github.com/mitmproxy/mitmproxy/issues/3609",N}i(Kt,"requestBody");function Gp(w){w=new RegExp(w,"i");function N(U){return!0}return i(N,"responseBodyFilter"),N.desc="body filters are not implemented yet, see https://github.com/mitmproxy/mitmproxy/issues/3609",N}i(Gp,"responseBody");function Cc(w){function N(U){return U.response&&U.response.status_code===w}return i(N,"responseCodeFilter"),N.desc="resp. code is "+w,N}i(Cc,"responseCode");function Zs(w){w=new RegExp(w,"i");function N(U){return w.test(U.comment)}return i(N,"commentFilter"),N.desc="comment matches "+w,N}i(Zs,"comment");function _c(w){w=new RegExp(w,"i");function N(U){return U.request&&(w.test(U.request.host)||w.test(U.request.pretty_host))}return i(N,"domainFilter"),N.desc="domain matches "+w,N}i(_c,"domain");function Ha(w){return w.type==="dns"}i(Ha,"dnsFilter"),Ha.desc="is a DNS Flow";function ed(w){w=new RegExp(w,"i");function N(U){return!!U.server_conn.address&&w.test(U.server_conn.address[0]+":"+U.server_conn.address[1])}return i(N,"destinationFilter"),N.desc="destination address matches "+w,N}i(ed,"destination");function Wl(w){return!!w.error}i(Wl,"errorFilter"),Wl.desc="has error";function $l(w){w=new RegExp(w,"i");function N(U){return U.request&&Bs.match_header(U.request,w)||U.response&&vl.match_header(U.response,w)}return i(N,"headerFilter"),N.desc="header matches "+w,N}i($l,"header");function Ec(w){w=new RegExp(w,"i");function N(U){return U.request&&Bs.match_header(U.request,w)}return i(N,"requestHeaderFilter"),N.desc="req. header matches "+w,N}i(Ec,"requestHeader");function Yp(w){w=new RegExp(w,"i");function N(U){return U.response&&vl.match_header(U.response,w)}return i(N,"responseHeaderFilter"),N.desc="resp. header matches "+w,N}i(Yp,"responseHeader");function Vl(w){return w.type==="http"}i(Vl,"httpFilter"),Vl.desc="is an HTTP Flow";function hn(w){return w.marked}i(hn,"markedFilter"),hn.desc="is marked";function bc(w){w=new RegExp(w,"i");function N(U){return w.test(U.marked)}return i(N,"markerFilter"),N.desc="marker matches "+w,N}i(bc,"marker");function co(w){w=new RegExp(w,"i");function N(U){return U.request&&w.test(U.request.method)}return i(N,"methodFilter"),N.desc="method matches "+w,N}i(co,"method");function yi(w){return w.request&&!w.response}i(yi,"noResponseFilter"),yi.desc="has no response";function ea(w){return w.is_replay==="request"}i(ea,"clientReplayFilter"),ea.desc="request has been replayed";function ql(w){return w.is_replay==="response"}i(ql,"serverReplayFilter"),ql.desc="response has been replayed";function Tc(w){return!!w.is_replay}i(Tc,"replayFilter"),Tc.desc="flow has been replayed";function Fi(w){w=new RegExp(w,"i");function N(U){return!!U.client_conn.peername&&w.test(U.client_conn.peername[0]+":"+U.client_conn.peername[1])}return i(N,"sourceFilter"),N.desc="source address matches "+w,N}i(Fi,"source");function $o(w){return!!w.response}i($o,"responseFilter"),$o.desc="has response";function jl(w){return w.type==="tcp"}i(jl,"tcpFilter"),jl.desc="is a TCP Flow";function xs(w){return w.type==="udp"}i(xs,"udpFilter"),xs.desc="is a UDP Flow";function td(w){w=new RegExp(w,"i");function N(U){return U.request&&w.test(Bs.getContentType(U.request))}return i(N,"requestContentTypeFilter"),N.desc="req. content type matches "+w,N}i(td,"requestContentType");function Xp(w){w=new RegExp(w,"i");function N(U){return U.response&&w.test(vl.getContentType(U.response))}return i(N,"responseContentTypeFilter"),N.desc="resp. content type matches "+w,N}i(Xp,"responseContentType");function Kl(w){w=new RegExp(w,"i");function N(U){return U.request&&w.test(Bs.getContentType(U.request))||U.response&&w.test(vl.getContentType(U.response))}return i(N,"contentTypeFilter"),N.desc="content type matches "+w,N}i(Kl,"contentType");function Gl(w){w=new RegExp(w,"i");function N(U){if(U.type==="dns"){let W=U.request?.questions[0];return W&&w.test(W.name)}return U.request&&w.test(Bs.pretty_url(U.request))}return i(N,"urlFilter"),N.desc="url matches "+w,N}i(Gl,"url");function Tn(w){return!!w.websocket}if(i(Tn,"websocketFilter"),Tn.desc="is a Websocket Flow",Ia=S(),Ia!==d&&M===s.length)return Ia;throw Ia!==d&&M1)s=s.filter(l=>l!==t.data);else if(s=[],t.data in e.viewIndex&&e.view.length>1){let l=e.viewIndex[t.data],h;l===e.view.length-1?h=e.view[l-1]:h=e.view[l+1],s.push(h.id)}}return{...e,selected:s,...$u(e,n)}}case FA:return{...e,filter:t.filter,...$u(e,km(DA(t.filter),Kx(e.sort)))};case HA:return{...e,highlight:t.highlight};case BA:return{...e,sort:t.sort,...$u(e,Fx(Kx(t.sort)))};case IA:return{...e,selected:t.flowIds};default:return e}}i(Gx,"reducer");function DA(e){if(e)return vf.parse(e)}i(DA,"makeFilter");function Kx({column:e,desc:t}){if(!e)return(s,l)=>0;let n=OA[e];return(s,l)=>{let h=n(s),d=n(l);return h>d?t?-1:1:hxt(`/flows/${e.id}/resume`,{method:"POST"})}i(lp,"resume");function $y(){return()=>xt("/flows/resume",{method:"POST"})}i($y,"resumeAll");function Vy(e){return()=>xt(`/flows/${e.id}/kill`,{method:"POST"})}i(Vy,"kill");function UA(){return()=>xt("/flows/kill",{method:"POST"})}i(UA,"killAll");function qy(e){return()=>xt(`/flows/${e.id}`,{method:"DELETE"})}i(qy,"remove");function jy(e){return()=>xt(`/flows/${e.id}/duplicate`,{method:"POST"})}i(jy,"duplicate");function up(e){return()=>xt(`/flows/${e.id}/replay`,{method:"POST"})}i(up,"replay");function Ky(e){return()=>xt(`/flows/${e.id}/revert`,{method:"POST"})}i(Ky,"revert");function si(e,t){return()=>xt.put(`/flows/${e.id}`,t)}i(si,"update");function WA(e,t,n){let s=new FormData;return t=new window.Blob([t],{type:"plain/text"}),s.append("file",t),()=>xt(`/flows/${e.id}/${n}/content.data`,{method:"POST",body:s})}i(WA,"uploadContent");function Gy(){return()=>xt("/clear",{method:"POST"})}i(Gy,"clear");function $A(e){let t=new FormData;return t.append("file",e),()=>xt("/flows/dump",{method:"POST",body:t})}i($A,"upload");function yl(e){return{type:IA,flowIds:e?[e]:[]}}i(yl,"select");var Yy="UI_HIDE_MODAL",VA="UI_SET_ACTIVE_MODAL",wB={activeModal:void 0};function Yx(e=wB,t){switch(t.type){case VA:return{...e,activeModal:t.activeModal};case Yy:return{...e,activeModal:void 0};default:return e}}i(Yx,"reducer");function qA(e){return{type:VA,activeModal:e}}i(qA,"setActiveModal");function Xy(){return{type:Yy}}i(Xy,"hideModal");var ba=pe(Te());var qt=pe(Te());var fp=pe(Te());var Lm=pe(Te()),KA=pe(ai());var jA=(()=>{let e=document.createElement("div");return e.setAttribute("contenteditable","PLAINTEXT-ONLY"),e.contentEditable==="plaintext-only"?"plaintext-only":"true"})(),cp=!1,gt=class extends Lm.Component{constructor(){super(...arguments);this.input=Lm.default.createRef();this.isEditing=i(()=>this.input.current?.contentEditable===jA,"isEditing");this.startEditing=i(()=>{if(!this.input.current)return console.error("unreachable");this.isEditing()||(this.suppress_events=!0,this.input.current.blur(),this.input.current.contentEditable=jA,window.requestAnimationFrame(()=>{if(!this.input.current)return;this.input.current.focus(),this.suppress_events=!1;let n=document.createRange();n.selectNodeContents(this.input.current);let s=window.getSelection();s?.removeAllRanges(),s?.addRange(n),this.props.onEditStart?.()}))},"startEditing");this.resetValue=i(()=>{if(!this.input.current)return console.error("unreachable");this.input.current.textContent=this.props.content,this.props.onInput?.(this.props.content)},"resetValue");this.finishEditing=i(()=>{if(!this.input.current)return console.error("unreachable");this.props.onEditDone(this.input.current.textContent||""),this.input.current.blur(),this.input.current.contentEditable="inherit"},"finishEditing");this.onPaste=i(n=>{n.preventDefault();let s=n.clipboardData.getData("text/plain");document.execCommand("insertHTML",!1,s)},"onPaste");this.suppress_events=!1;this.onMouseDown=i(n=>{cp&&console.debug("onMouseDown",this.suppress_events),this.suppress_events=!0,window.addEventListener("mouseup",this.onMouseUp,{once:!0})},"onMouseDown");this.onMouseUp=i(n=>{let s=n.target===this.input.current,l=!window.getSelection()?.toString();cp&&console.warn("mouseUp",this.suppress_events,s,l),s&&l&&this.startEditing(),this.suppress_events=!1},"onMouseUp");this.onClick=i(n=>{cp&&console.debug("onClick",this.suppress_events)},"onClick");this.onFocus=i(n=>{if(cp&&console.debug("onFocus",this.props.content,this.suppress_events),!this.input.current)throw"unreachable";this.suppress_events||this.startEditing()},"onFocus");this.onInput=i(n=>{this.props.onInput?.(this.input.current?.textContent||"")},"onInput");this.onBlur=i(n=>{cp&&console.debug("onBlur",this.props.content,this.suppress_events),!this.suppress_events&&this.finishEditing()},"onBlur");this.onKeyDown=i(n=>{switch(cp&&console.debug("keydown",n),n.stopPropagation(),n.key){case"Escape":n.preventDefault(),this.resetValue(),this.finishEditing();break;case"Enter":n.shiftKey||(n.preventDefault(),this.finishEditing());break;default:break}this.props.onKeyDown?.(n)},"onKeyDown")}static{i(this,"ValueEditor")}render(){let n=(0,KA.default)("inline-input",this.props.className);return Lm.default.createElement("span",{ref:this.input,tabIndex:0,className:n,placeholder:this.props.placeholder,onFocus:this.onFocus,onBlur:this.onBlur,onKeyDown:this.onKeyDown,onInput:this.onInput,onPaste:this.onPaste,onMouseDown:this.onMouseDown,onClick:this.onClick},this.props.content)}componentDidUpdate(n){n.content!==this.props.content&&this.props.onInput?.(this.props.content)}};var GA=pe(ai());function wf(e){let[t,n]=(0,fp.useState)(e.isValid(e.content)),s=(0,fp.useRef)(null),l=i(d=>{e.isValid(d)?e.onEditDone(d):s.current?.resetValue()},"onEditDone"),h=(0,GA.default)(e.className,t?"has-success":"has-warning");return fp.default.createElement(gt,{...e,className:h,onInput:d=>n(e.isValid(d)),onEditDone:l,ref:s})}i(wf,"ValidateEditor");function Kn(e){return`Minified Redux error #${e}; visit https://redux.js.org/Errors?code=${e} for the full message or use the non-minified dev environment for full errors. `}i(Kn,"formatProdErrorMessage");var SB=typeof Symbol=="function"&&Symbol.observable||"@@observable",YA=SB,Qx=i(()=>Math.random().toString(36).substring(7).split("").join("."),"randomString"),xB={INIT:`@@redux/INIT${Qx()}`,REPLACE:`@@redux/REPLACE${Qx()}`,PROBE_UNKNOWN_ACTION:i(()=>`@@redux/PROBE_UNKNOWN_ACTION${Qx()}`,"PROBE_UNKNOWN_ACTION")},Jy=xB;function Zy(e){if(typeof e!="object"||e===null)return!1;let t=e;for(;Object.getPrototypeOf(t)!==null;)t=Object.getPrototypeOf(t);return Object.getPrototypeOf(e)===t||Object.getPrototypeOf(e)===null}i(Zy,"isPlainObject");function Jx(e,t,n){if(typeof e!="function")throw new Error(Kn(2));if(typeof t=="function"&&typeof n=="function"||typeof n=="function"&&typeof arguments[3]=="function")throw new Error(Kn(0));if(typeof t=="function"&&typeof n>"u"&&(n=t,t=void 0),typeof n<"u"){if(typeof n!="function")throw new Error(Kn(1));return n(Jx)(e,t)}let s=e,l=t,h=new Map,d=h,v=0,S=!1;function b(){d===h&&(d=new Map,h.forEach((ne,D)=>{d.set(D,ne)}))}i(b,"ensureCanMutateNextListeners");function k(){if(S)throw new Error(Kn(3));return l}i(k,"getState");function R(ne){if(typeof ne!="function")throw new Error(Kn(4));if(S)throw new Error(Kn(5));let D=!0;b();let L=v++;return d.set(L,ne),i(function(){if(D){if(S)throw new Error(Kn(6));D=!1,b(),d.delete(L),h=null}},"unsubscribe")}i(R,"subscribe");function I(ne){if(!Zy(ne))throw new Error(Kn(7));if(typeof ne.type>"u")throw new Error(Kn(8));if(typeof ne.type!="string")throw new Error(Kn(17));if(S)throw new Error(Kn(9));try{S=!0,l=s(l,ne)}finally{S=!1}return(h=d).forEach(L=>{L()}),ne}i(I,"dispatch");function z(ne){if(typeof ne!="function")throw new Error(Kn(10));s=ne,I({type:Jy.REPLACE})}i(z,"replaceReducer");function q(){let ne=R;return{subscribe(D){if(typeof D!="object"||D===null)throw new Error(Kn(11));function L(){let j=D;j.next&&j.next(k())}return i(L,"observeState"),L(),{unsubscribe:ne(L)}},[YA](){return this}}}return i(q,"observable"),I({type:Jy.INIT}),{dispatch:I,subscribe:R,getState:k,replaceReducer:z,[YA]:q}}i(Jx,"createStore");function CB(e){Object.keys(e).forEach(t=>{let n=e[t];if(typeof n(void 0,{type:Jy.INIT})>"u")throw new Error(Kn(12));if(typeof n(void 0,{type:Jy.PROBE_UNKNOWN_ACTION()})>"u")throw new Error(Kn(13))})}i(CB,"assertReducerShape");function dp(e){let t=Object.keys(e),n={};for(let d=0;d"u"){let ne=S&&S.type;throw new Error(Kn(14))}k[I]=Q,b=b||Q!==q}return b=b||s.length!==Object.keys(v).length,b?k:v},"combination")}i(dp,"combineReducers");function pp(...e){return e.length===0?t=>t:e.length===1?e[0]:e.reduce((t,n)=>(...s)=>t(n(...s)))}i(pp,"compose");function XA(...e){return t=>(n,s)=>{let l=t(n,s),h=i(()=>{throw new Error(Kn(15))},"dispatch"),d={getState:l.getState,dispatch:i((S,...b)=>h(S,...b),"dispatch")},v=e.map(S=>S(d));return h=pp(...v)(l.dispatch),{...l,dispatch:h}}}i(XA,"applyMiddleware");function QA(e){return Zy(e)&&"type"in e&&typeof e.type=="string"}i(QA,"isAction");var nP=Symbol.for("immer-nothing"),JA=Symbol.for("immer-draftable"),Ro=Symbol.for("immer-state");function Hs(e,...t){throw new Error(`[Immer] minified error nr: ${e}. Full error at: https://bit.ly/3cXEKWf`)}i(Hs,"die");var hp=Object.getPrototypeOf;function _a(e){return!!e&&!!e[Ro]}i(_a,"isDraft");function zs(e){return e?iP(e)||Array.isArray(e)||!!e[JA]||!!e.constructor?.[JA]||i0(e)||o0(e):!1}i(zs,"isDraftable");var _B=Object.prototype.constructor.toString();function iP(e){if(!e||typeof e!="object")return!1;let t=hp(e);if(t===null)return!0;let n=Object.hasOwnProperty.call(t,"constructor")&&t.constructor;return n===Object?!0:typeof n=="function"&&Function.toString.call(n)===_B}i(iP,"isPlainObject");function e0(e,t){n0(e)===0?Reflect.ownKeys(e).forEach(n=>{t(n,e[n],e)}):e.forEach((n,s)=>t(s,n,e))}i(e0,"each");function n0(e){let t=e[Ro];return t?t.type_:Array.isArray(e)?1:i0(e)?2:o0(e)?3:0}i(n0,"getArchtype");function tC(e,t){return n0(e)===2?e.has(t):Object.prototype.hasOwnProperty.call(e,t)}i(tC,"has");function oP(e,t,n){let s=n0(e);s===2?e.set(t,n):s===3?e.add(n):e[t]=n}i(oP,"set");function EB(e,t){return e===t?e!==0||1/e===1/t:e!==e&&t!==t}i(EB,"is");function i0(e){return e instanceof Map}i(i0,"isMap");function o0(e){return e instanceof Set}i(o0,"isSet");function Sf(e){return e.copy_||e.base_}i(Sf,"latest");function rC(e,t){if(i0(e))return new Map(e);if(o0(e))return new Set(e);if(Array.isArray(e))return Array.prototype.slice.call(e);let n=iP(e);if(t===!0||t==="class_only"&&!n){let s=Object.getOwnPropertyDescriptors(e);delete s[Ro];let l=Reflect.ownKeys(s);for(let h=0;h1&&(e.set=e.add=e.clear=e.delete=bB),Object.freeze(e),t&&Object.entries(e).forEach(([n,s])=>aC(s,!0))),e}i(aC,"freeze");function bB(){Hs(2)}i(bB,"dontMutateFrozenCollections");function s0(e){return Object.isFrozen(e)}i(s0,"isFrozen");var TB={};function xf(e){let t=TB[e];return t||Hs(0,e),t}i(xf,"getPlugin");var Mm;function sP(){return Mm}i(sP,"getCurrentScope");function kB(e,t){return{drafts_:[],parent_:e,immer_:t,canAutoFreeze_:!0,unfinalizedDrafts_:0}}i(kB,"createScope");function ZA(e,t){t&&(xf("Patches"),e.patches_=[],e.inversePatches_=[],e.patchListener_=t)}i(ZA,"usePatchesInScope");function nC(e){iC(e),e.drafts_.forEach(NB),e.drafts_=null}i(nC,"revokeScope");function iC(e){e===Mm&&(Mm=e.parent_)}i(iC,"leaveScope");function eP(e){return Mm=kB(Mm,e)}i(eP,"enterScope");function NB(e){let t=e[Ro];t.type_===0||t.type_===1?t.revoke_():t.revoked_=!0}i(NB,"revokeDraft");function tP(e,t){t.unfinalizedDrafts_=t.drafts_.length;let n=t.drafts_[0];return e!==void 0&&e!==n?(n[Ro].modified_&&(nC(t),Hs(4)),zs(e)&&(e=t0(t,e),t.parent_||r0(t,e)),t.patches_&&xf("Patches").generateReplacementPatches_(n[Ro].base_,e,t.patches_,t.inversePatches_)):e=t0(t,n,[]),nC(t),t.patches_&&t.patchListener_(t.patches_,t.inversePatches_),e!==nP?e:void 0}i(tP,"processResult");function t0(e,t,n){if(s0(t))return t;let s=t[Ro];if(!s)return e0(t,(l,h)=>rP(e,s,t,l,h,n)),t;if(s.scope_!==e)return t;if(!s.modified_)return r0(e,s.base_,!0),s.base_;if(!s.finalized_){s.finalized_=!0,s.scope_.unfinalizedDrafts_--;let l=s.copy_,h=l,d=!1;s.type_===3&&(h=new Set(l),l.clear(),d=!0),e0(h,(v,S)=>rP(e,s,l,v,S,n,d)),r0(e,l,!1),n&&e.patches_&&xf("Patches").generatePatches_(s,n,e.patches_,e.inversePatches_)}return s.copy_}i(t0,"finalize");function rP(e,t,n,s,l,h,d){if(_a(l)){let v=h&&t&&t.type_!==3&&!tC(t.assigned_,s)?h.concat(s):void 0,S=t0(e,l,v);if(oP(n,s,S),_a(S))e.canAutoFreeze_=!1;else return}else d&&n.add(l);if(zs(l)&&!s0(l)){if(!e.immer_.autoFreeze_&&e.unfinalizedDrafts_<1)return;t0(e,l),(!t||!t.scope_.parent_)&&typeof s!="symbol"&&Object.prototype.propertyIsEnumerable.call(n,s)&&r0(e,l)}}i(rP,"finalizeProperty");function r0(e,t,n=!1){!e.parent_&&e.immer_.autoFreeze_&&e.canAutoFreeze_&&aC(t,n)}i(r0,"maybeFreeze");function AB(e,t){let n=Array.isArray(e),s={type_:n?1:0,scope_:t?t.scope_:sP(),modified_:!1,finalized_:!1,assigned_:{},parent_:t,base_:e,draft_:null,copy_:null,revoke_:null,isManual_:!1},l=s,h=lC;n&&(l=[s],h=Om);let{revoke:d,proxy:v}=Proxy.revocable(l,h);return s.draft_=v,s.revoke_=d,v}i(AB,"createProxyProxy");var lC={get(e,t){if(t===Ro)return e;let n=Sf(e);if(!tC(n,t))return PB(e,n,t);let s=n[t];return e.finalized_||!zs(s)?s:s===Zx(e.base_,t)?(eC(e),e.copy_[t]=sC(s,e)):s},has(e,t){return t in Sf(e)},ownKeys(e){return Reflect.ownKeys(Sf(e))},set(e,t,n){let s=aP(Sf(e),t);if(s?.set)return s.set.call(e.draft_,n),!0;if(!e.modified_){let l=Zx(Sf(e),t),h=l?.[Ro];if(h&&h.base_===n)return e.copy_[t]=n,e.assigned_[t]=!1,!0;if(EB(n,l)&&(n!==void 0||tC(e.base_,t)))return!0;eC(e),oC(e)}return e.copy_[t]===n&&(n!==void 0||t in e.copy_)||Number.isNaN(n)&&Number.isNaN(e.copy_[t])||(e.copy_[t]=n,e.assigned_[t]=!0),!0},deleteProperty(e,t){return Zx(e.base_,t)!==void 0||t in e.base_?(e.assigned_[t]=!1,eC(e),oC(e)):delete e.assigned_[t],e.copy_&&delete e.copy_[t],!0},getOwnPropertyDescriptor(e,t){let n=Sf(e),s=Reflect.getOwnPropertyDescriptor(n,t);return s&&{writable:!0,configurable:e.type_!==1||t!=="length",enumerable:s.enumerable,value:n[t]}},defineProperty(){Hs(11)},getPrototypeOf(e){return hp(e.base_)},setPrototypeOf(){Hs(12)}},Om={};e0(lC,(e,t)=>{Om[e]=function(){return arguments[0]=arguments[0][0],t.apply(this,arguments)}});Om.deleteProperty=function(e,t){return Om.set.call(this,e,t,void 0)};Om.set=function(e,t,n){return lC.set.call(this,e[0],t,n,e[0])};function Zx(e,t){let n=e[Ro];return(n?Sf(n):e)[t]}i(Zx,"peek");function PB(e,t,n){let s=aP(t,n);return s?"value"in s?s.value:s.get?.call(e.draft_):void 0}i(PB,"readPropFromProto");function aP(e,t){if(!(t in e))return;let n=hp(e);for(;n;){let s=Object.getOwnPropertyDescriptor(n,t);if(s)return s;n=hp(n)}}i(aP,"getDescriptorFromProto");function oC(e){e.modified_||(e.modified_=!0,e.parent_&&oC(e.parent_))}i(oC,"markChanged");function eC(e){e.copy_||(e.copy_=rC(e.base_,e.scope_.immer_.useStrictShallowCopy_))}i(eC,"prepareCopy");var LB=class{static{i(this,"Immer2")}constructor(e){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.produce=(t,n,s)=>{if(typeof t=="function"&&typeof n!="function"){let h=n;n=t;let d=this;return i(function(S=h,...b){return d.produce(S,k=>n.call(this,k,...b))},"curriedProduce")}typeof n!="function"&&Hs(6),s!==void 0&&typeof s!="function"&&Hs(7);let l;if(zs(t)){let h=eP(this),d=sC(t,void 0),v=!0;try{l=n(d),v=!1}finally{v?nC(h):iC(h)}return ZA(h,s),tP(l,h)}else if(!t||typeof t!="object"){if(l=n(t),l===void 0&&(l=t),l===nP&&(l=void 0),this.autoFreeze_&&aC(l,!0),s){let h=[],d=[];xf("Patches").generateReplacementPatches_(t,l,h,d),s(h,d)}return l}else Hs(1,t)},this.produceWithPatches=(t,n)=>{if(typeof t=="function")return(d,...v)=>this.produceWithPatches(d,S=>t(S,...v));let s,l;return[this.produce(t,n,(d,v)=>{s=d,l=v}),s,l]},typeof e?.autoFreeze=="boolean"&&this.setAutoFreeze(e.autoFreeze),typeof e?.useStrictShallowCopy=="boolean"&&this.setUseStrictShallowCopy(e.useStrictShallowCopy)}createDraft(e){zs(e)||Hs(8),_a(e)&&(e=uC(e));let t=eP(this),n=sC(e,void 0);return n[Ro].isManual_=!0,iC(t),n}finishDraft(e,t){let n=e&&e[Ro];(!n||!n.isManual_)&&Hs(9);let{scope_:s}=n;return ZA(s,t),tP(void 0,s)}setAutoFreeze(e){this.autoFreeze_=e}setUseStrictShallowCopy(e){this.useStrictShallowCopy_=e}applyPatches(e,t){let n;for(n=t.length-1;n>=0;n--){let l=t[n];if(l.path.length===0&&l.op==="replace"){e=l.value;break}}n>-1&&(t=t.slice(n+1));let s=xf("Patches").applyPatches_;return _a(e)?s(e,t):this.produce(e,l=>s(l,t))}};function sC(e,t){let n=i0(e)?xf("MapSet").proxyMap_(e,t):o0(e)?xf("MapSet").proxySet_(e,t):AB(e,t);return(t?t.scope_:sP()).drafts_.push(n),n}i(sC,"createProxy");function uC(e){return _a(e)||Hs(10,e),lP(e)}i(uC,"current");function lP(e){if(!zs(e)||s0(e))return e;let t=e[Ro],n;if(t){if(!t.modified_)return t.base_;t.finalized_=!0,n=rC(e,t.scope_.immer_.useStrictShallowCopy_)}else n=rC(e,!0);return e0(n,(s,l)=>{oP(n,s,lP(l))}),t&&(t.finalized_=!1),n}i(lP,"currentImpl");var Do=new LB,a0=Do.produce,w8=Do.produceWithPatches.bind(Do),S8=Do.setAutoFreeze.bind(Do),x8=Do.setUseStrictShallowCopy.bind(Do),C8=Do.applyPatches.bind(Do),_8=Do.createDraft.bind(Do),E8=Do.finishDraft.bind(Do);function MB(e,t=`expected a function, instead received ${typeof e}`){if(typeof e!="function")throw new TypeError(t)}i(MB,"assertIsFunction");function OB(e,t=`expected an object, instead received ${typeof e}`){if(typeof e!="object")throw new TypeError(t)}i(OB,"assertIsObject");function RB(e,t="expected all items to be functions, instead received the following types: "){if(!e.every(n=>typeof n=="function")){let n=e.map(s=>typeof s=="function"?`function ${s.name||"unnamed"}()`:typeof s).join(", ");throw new TypeError(`${t}[${n}]`)}}i(RB,"assertIsArrayOfFunctions");var uP=i(e=>Array.isArray(e)?e:[e],"ensureIsArray");function DB(e){let t=Array.isArray(e[0])?e[0]:e;return RB(t,"createSelector expects all input-selectors to be functions, but received the following types: "),t}i(DB,"getDependencies");function IB(e,t){let n=[],{length:s}=e;for(let l=0;l{n=l0(),d.resetResultsCount()},d.resultsCount=()=>h,d.resetResultsCount=()=>{h=0},d}i(u0,"weakMapMemoize");function cC(e,...t){let n=typeof e=="function"?{memoize:e,memoizeOptions:t}:e,s=i((...l)=>{let h=0,d=0,v,S={},b=l.pop();typeof b=="object"&&(S=b,b=l.pop()),MB(b,`createSelector expects an output function after the inputs, but received: [${typeof b}]`);let k={...n,...S},{memoize:R,memoizeOptions:I=[],argsMemoize:z=u0,argsMemoizeOptions:q=[],devModeChecks:Q={}}=k,ne=uP(I),D=uP(q),L=DB(l),B=R(i(function(){return h++,b.apply(null,arguments)},"recomputationWrapper"),...ne),j=!0,re=z(i(function(){d++;let oe=IB(L,arguments);return v=B.apply(null,oe),v},"dependenciesChecker"),...D);return Object.assign(re,{resultFunc:b,memoizedResultFunc:B,dependencies:L,dependencyRecomputations:i(()=>d,"dependencyRecomputations"),resetDependencyRecomputations:i(()=>{d=0},"resetDependencyRecomputations"),lastResult:i(()=>v,"lastResult"),recomputations:i(()=>h,"recomputations"),resetRecomputations:i(()=>{h=0},"resetRecomputations"),memoize:R,argsMemoize:z})},"createSelector2");return Object.assign(s,{withTypes:i(()=>s,"withTypes")}),s}i(cC,"createSelectorCreator");var zB=cC(u0),UB=Object.assign((e,t=zB)=>{OB(e,`createStructuredSelector expects first argument to be an object where each property is a selector, instead received a ${typeof e}`);let n=Object.keys(e),s=n.map(h=>e[h]);return t(s,(...h)=>h.reduce((d,v,S)=>(d[n[S]]=v,d),{}))},{withTypes:i(()=>UB,"withTypes")});function fP(e){return i(({dispatch:n,getState:s})=>l=>h=>typeof h=="function"?h(n,s,e):l(h),"middleware")}i(fP,"createThunkMiddleware");var dP=fP(),pP=fP;var WB=i((...e)=>{let t=cC(...e),n=Object.assign((...s)=>{let l=t(...s),h=i((d,...v)=>l(_a(d)?uC(d):d,...v),"wrappedSelector");return Object.assign(h,l),h},{withTypes:i(()=>n,"withTypes")});return n},"createDraftSafeSelectorCreator"),F8=WB(u0),$B=typeof window<"u"&&window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__:function(){if(arguments.length!==0)return typeof arguments[0]=="object"?pp:pp.apply(null,arguments)},z8=typeof window<"u"&&window.__REDUX_DEVTOOLS_EXTENSION__?window.__REDUX_DEVTOOLS_EXTENSION__:function(){return function(e){return e}},VB=i(e=>e&&typeof e.match=="function","hasMatchFunction");function us(e,t){function n(...s){if(t){let l=t(...s);if(!l)throw new Error(rn(0));return{type:e,payload:l.payload,..."meta"in l&&{meta:l.meta},..."error"in l&&{error:l.error}}}return{type:e,payload:s[0]}}return i(n,"actionCreator"),n.toString=()=>`${e}`,n.type=e,n.match=s=>QA(s)&&s.type===e,n}i(us,"createAction");var vP=class Rm extends Array{static{i(this,"_Tuple")}constructor(...t){super(...t),Object.setPrototypeOf(this,Rm.prototype)}static get[Symbol.species](){return Rm}concat(...t){return super.concat.apply(this,t)}prepend(...t){return t.length===1&&Array.isArray(t[0])?new Rm(...t[0].concat(this)):new Rm(...t.concat(this))}};function hP(e){return zs(e)?a0(e,()=>{}):e}i(hP,"freezeDraftable");function mP(e,t,n){if(e.has(t)){let l=e.get(t);return n.update&&(l=n.update(l,t,e),e.set(t,l)),l}if(!n.insert)throw new Error(rn(10));let s=n.insert(t,e);return e.set(t,s),s}i(mP,"emplace");function qB(e){return typeof e=="boolean"}i(qB,"isBoolean");var jB=i(()=>i(function(t){let{thunk:n=!0,immutableCheck:s=!0,serializableCheck:l=!0,actionCreatorCheck:h=!0}=t??{},d=new vP;return n&&(qB(n)?d.push(dP):d.push(pP(n.extraArgument))),d},"getDefaultMiddleware"),"buildGetDefaultMiddleware"),KB="RTK_autoBatch";var yP=i(e=>t=>{setTimeout(t,e)},"createQueueWithTimer"),GB=typeof window<"u"&&window.requestAnimationFrame?window.requestAnimationFrame:yP(10),YB=i((e={type:"raf"})=>t=>(...n)=>{let s=t(...n),l=!0,h=!1,d=!1,v=new Set,S=e.type==="tick"?queueMicrotask:e.type==="raf"?GB:e.type==="callback"?e.queueNotification:yP(e.timeout),b=i(()=>{d=!1,h&&(h=!1,v.forEach(k=>k()))},"notifyListeners");return Object.assign({},s,{subscribe(k){let R=i(()=>l&&k(),"wrappedListener"),I=s.subscribe(R);return v.add(k),()=>{I(),v.delete(k)}},dispatch(k){try{return l=!k?.meta?.[KB],h=!l,h&&(d||(d=!0,S(b))),s.dispatch(k)}finally{l=!0}}})},"autoBatchEnhancer"),XB=i(e=>i(function(n){let{autoBatch:s=!0}=n??{},l=new vP(e);return s&&l.push(YB(typeof s=="object"?s:void 0)),l},"getDefaultEnhancers"),"buildGetDefaultEnhancers"),Vu=!0;function wP(e){let t=jB(),{reducer:n=void 0,middleware:s,devTools:l=!0,preloadedState:h=void 0,enhancers:d=void 0}=e||{},v;if(typeof n=="function")v=n;else if(Zy(n))v=dp(n);else throw new Error(rn(1));if(!Vu&&s&&typeof s!="function")throw new Error(rn(2));let S;if(typeof s=="function"){if(S=s(t),!Vu&&!Array.isArray(S))throw new Error(rn(3))}else S=t();if(!Vu&&S.some(q=>typeof q!="function"))throw new Error(rn(4));let b=pp;l&&(b=$B({trace:!Vu,...typeof l=="object"&&l}));let k=XA(...S),R=XB(k);if(!Vu&&d&&typeof d!="function")throw new Error(rn(5));let I=typeof d=="function"?d(R):R();if(!Vu&&!Array.isArray(I))throw new Error(rn(6));if(!Vu&&I.some(q=>typeof q!="function"))throw new Error(rn(7));!Vu&&S.length&&!I.includes(k)&&console.error("middlewares were provided, but middleware enhancer was not included in final enhancers - make sure to call `getDefaultEnhancers`");let z=b(...I);return Jx(v,h,z)}i(wP,"configureStore");function SP(e){let t={},n=[],s,l={addCase(h,d){let v=typeof h=="string"?h:h.type;if(!v)throw new Error(rn(28));if(v in t)throw new Error(rn(29));return t[v]=d,l},addMatcher(h,d){return n.push({matcher:h,reducer:d}),l},addDefaultCase(h){return s=h,l}};return e(l),[t,n,s]}i(SP,"executeReducerBuilderCallback");function QB(e){return typeof e=="function"}i(QB,"isStateFunction");function JB(e,t){let[n,s,l]=SP(t),h;if(QB(e))h=i(()=>hP(e()),"getInitialState");else{let v=hP(e);h=i(()=>v,"getInitialState")}function d(v=h(),S){let b=[n[S.type],...s.filter(({matcher:k})=>k(S)).map(({reducer:k})=>k)];return b.filter(k=>!!k).length===0&&(b=[l]),b.reduce((k,R)=>{if(R)if(_a(k)){let z=R(k,S);return z===void 0?k:z}else{if(zs(k))return a0(k,I=>R(I,S));{let I=R(k,S);if(I===void 0){if(k===null)return k;throw new Error(rn(9))}return I}}return k},v)}return i(d,"reducer"),d.getInitialState=h,d}i(JB,"createReducer");var ZB="ModuleSymbhasOwnPr-0123456789ABCDEFGHNRVfgctiUvz_KqYTJkLxpZXIjQW",xP=i((e=21)=>{let t="",n=e;for(;n--;)t+=ZB[Math.random()*64|0];return t},"nanoid"),eH=i((e,t)=>VB(e)?e.match(t):e(t),"matches");function tH(...e){return t=>e.some(n=>eH(n,t))}i(tH,"isAnyOf");var rH=["name","message","stack","code"],fC=class{static{i(this,"RejectWithValue")}constructor(e,t){this.payload=e,this.meta=t}_type},gP=class{static{i(this,"FulfillWithMeta")}constructor(e,t){this.payload=e,this.meta=t}_type},nH=i(e=>{if(typeof e=="object"&&e!==null){let t={};for(let n of rH)typeof e[n]=="string"&&(t[n]=e[n]);return t}return{message:String(e)}},"miniSerializeError"),Dm=(()=>{function e(t,n,s){let l=us(t+"/fulfilled",(S,b,k,R)=>({payload:S,meta:{...R||{},arg:k,requestId:b,requestStatus:"fulfilled"}})),h=us(t+"/pending",(S,b,k)=>({payload:void 0,meta:{...k||{},arg:b,requestId:S,requestStatus:"pending"}})),d=us(t+"/rejected",(S,b,k,R,I)=>({payload:R,error:(s&&s.serializeError||nH)(S||"Rejected"),meta:{...I||{},arg:k,requestId:b,rejectedWithValue:!!R,requestStatus:"rejected",aborted:S?.name==="AbortError",condition:S?.name==="ConditionError"}}));function v(S){return(b,k,R)=>{let I=s?.idGenerator?s.idGenerator(S):xP(),z=new AbortController,q,Q;function ne(L){Q=L,z.abort()}i(ne,"abort");let D=async function(){let L;try{let j=s?.condition?.(S,{getState:k,extra:R});if(oH(j)&&(j=await j),j===!1||z.signal.aborted)throw{name:"ConditionError",message:"Aborted due to condition callback returning false."};let re=new Promise((Z,oe)=>{q=i(()=>{oe({name:"AbortError",message:Q||"Aborted"})},"abortHandler"),z.signal.addEventListener("abort",q)});b(h(I,S,s?.getPendingMeta?.({requestId:I,arg:S},{getState:k,extra:R}))),L=await Promise.race([re,Promise.resolve(n(S,{dispatch:b,getState:k,extra:R,requestId:I,signal:z.signal,abort:ne,rejectWithValue:i((Z,oe)=>new fC(Z,oe),"rejectWithValue"),fulfillWithValue:i((Z,oe)=>new gP(Z,oe),"fulfillWithValue")})).then(Z=>{if(Z instanceof fC)throw Z;return Z instanceof gP?l(Z.payload,I,S,Z.meta):l(Z,I,S)})])}catch(j){L=j instanceof fC?d(null,I,S,j.payload,j.meta):d(j,I,S)}finally{q&&z.signal.removeEventListener("abort",q)}return s&&!s.dispatchConditionRejection&&d.match(L)&&L.meta.condition||b(L),L}();return Object.assign(D,{abort:ne,requestId:I,arg:S,unwrap(){return D.then(iH)}})}}return i(v,"actionCreator"),Object.assign(v,{pending:h,rejected:d,fulfilled:l,settled:tH(d,l),typePrefix:t})}return i(e,"createAsyncThunk2"),e.withTypes=()=>e,e})();function iH(e){if(e.meta&&e.meta.rejectedWithValue)throw e.payload;if(e.error)throw e.error;return e.payload}i(iH,"unwrapResult");function oH(e){return e!==null&&typeof e=="object"&&typeof e.then=="function"}i(oH,"isThenable");var CP=Symbol.for("rtk-slice-createasyncthunk"),q8={[CP]:Dm};function sH(e,t){return`${e}/${t}`}i(sH,"getType");function aH({creators:e}={}){let t=e?.asyncThunk?.[CP];return i(function(s){let{name:l,reducerPath:h=l}=s;if(!l)throw new Error(rn(11));typeof process<"u";let d=(typeof s.reducers=="function"?s.reducers(uH()):s.reducers)||{},v=Object.keys(d),S={sliceCaseReducersByName:{},sliceCaseReducersByType:{},actionCreators:{},sliceMatchers:[]},b={addCase(L,B){let j=typeof L=="string"?L:L.type;if(!j)throw new Error(rn(12));if(j in S.sliceCaseReducersByType)throw new Error(rn(13));return S.sliceCaseReducersByType[j]=B,b},addMatcher(L,B){return S.sliceMatchers.push({matcher:L,reducer:B}),b},exposeAction(L,B){return S.actionCreators[L]=B,b},exposeCaseReducer(L,B){return S.sliceCaseReducersByName[L]=B,b}};v.forEach(L=>{let B=d[L],j={reducerName:L,type:sH(l,L),createNotation:typeof s.reducers=="function"};fH(B)?pH(j,B,b,t):cH(j,B,b)});function k(){let[L={},B=[],j=void 0]=typeof s.extraReducers=="function"?SP(s.extraReducers):[s.extraReducers],re={...L,...S.sliceCaseReducersByType};return JB(s.initialState,Z=>{for(let oe in re)Z.addCase(oe,re[oe]);for(let oe of S.sliceMatchers)Z.addMatcher(oe.matcher,oe.reducer);for(let oe of B)Z.addMatcher(oe.matcher,oe.reducer);j&&Z.addDefaultCase(j)})}i(k,"buildReducer");let R=i(L=>L,"selectSelf"),I=new Map,z;function q(L,B){return z||(z=k()),z(L,B)}i(q,"reducer");function Q(){return z||(z=k()),z.getInitialState()}i(Q,"getInitialState");function ne(L,B=!1){function j(Z){let oe=Z[L];return typeof oe>"u"&&B&&(oe=Q()),oe}i(j,"selectSlice");function re(Z=R){let oe=mP(I,B,{insert:i(()=>new WeakMap,"insert")});return mP(oe,Z,{insert:i(()=>{let he={};for(let[Re,Ee]of Object.entries(s.selectors??{}))he[Re]=lH(Ee,Z,Q,B);return he},"insert")})}return i(re,"getSelectors"),{reducerPath:L,getSelectors:re,get selectors(){return re(j)},selectSlice:j}}i(ne,"makeSelectorProps");let D={name:l,reducer:q,actions:S.actionCreators,caseReducers:S.sliceCaseReducersByName,getInitialState:Q,...ne(h),injectInto(L,{reducerPath:B,...j}={}){let re=B??h;return L.inject({reducerPath:re,reducer:q},j),{...D,...ne(re,!0)}}};return D},"createSlice2")}i(aH,"buildCreateSlice");function lH(e,t,n,s){function l(h,...d){let v=t(h);return typeof v>"u"&&s&&(v=n()),e(v,...d)}return i(l,"wrapper"),l.unwrapped=e,l}i(lH,"wrapSelector");var nn=aH();function uH(){function e(t,n){return{_reducerDefinitionType:"asyncThunk",payloadCreator:t,...n}}return i(e,"asyncThunk"),e.withTypes=()=>e,{reducer(t){return Object.assign({[t.name](...n){return t(...n)}}[t.name],{_reducerDefinitionType:"reducer"})},preparedReducer(t,n){return{_reducerDefinitionType:"reducerWithPrepare",prepare:t,reducer:n}},asyncThunk:e}}i(uH,"buildReducerCreators");function cH({type:e,reducerName:t,createNotation:n},s,l){let h,d;if("reducer"in s){if(n&&!dH(s))throw new Error(rn(17));h=s.reducer,d=s.prepare}else h=s;l.addCase(e,h).exposeCaseReducer(t,h).exposeAction(t,d?us(e,d):us(e))}i(cH,"handleNormalReducerDefinition");function fH(e){return e._reducerDefinitionType==="asyncThunk"}i(fH,"isAsyncThunkSliceReducerDefinition");function dH(e){return e._reducerDefinitionType==="reducerWithPrepare"}i(dH,"isCaseReducerWithPrepareDefinition");function pH({type:e,reducerName:t},n,s,l){if(!l)throw new Error(rn(18));let{payloadCreator:h,fulfilled:d,pending:v,rejected:S,settled:b,options:k}=n,R=l(e,h,k);s.exposeAction(t,R),d&&s.addCase(R.fulfilled,d),v&&s.addCase(R.pending,v),S&&s.addCase(R.rejected,S),b&&s.addMatcher(R.settled,b),s.exposeCaseReducer(t,{fulfilled:d||c0,pending:v||c0,rejected:S||c0,settled:b||c0})}i(pH,"handleThunkCaseReducerDefinition");function c0(){}i(c0,"noop");var _P="listener",EP="completed",bP="cancelled",j8=`task-${bP}`,K8=`task-${EP}`,G8=`${_P}-${bP}`,Y8=`${_P}-${EP}`;var hH=i((e,t)=>{if(typeof e!="function")throw new Error(rn(32))},"assertFunction");var{assign:X8}=Object;var dC="listenerMiddleware";var mH=i(e=>{let{type:t,actionCreator:n,matcher:s,predicate:l,effect:h}=e;if(t)l=us(t).match;else if(n)t=n.type,l=n.match;else if(s)l=s;else if(!l)throw new Error(rn(21));return hH(h,"options.listener"),{predicate:l,type:t,effect:h}},"getListenerEntryPropsFrom"),gH=Object.assign(e=>{let{type:t,predicate:n,effect:s}=mH(e);return{id:xP(),effect:s,type:t,predicate:n,pending:new Set,unsubscribe:i(()=>{throw new Error(rn(22))},"unsubscribe")}},{withTypes:i(()=>gH,"withTypes")});var vH=Object.assign(us(`${dC}/add`),{withTypes:i(()=>vH,"withTypes")}),Q8=us(`${dC}/removeAll`),yH=Object.assign(us(`${dC}/remove`),{withTypes:i(()=>yH,"withTypes")});var J8=Symbol.for("rtk-state-proxy-original");function rn(e){return`Minified Redux Toolkit error #${e}; visit https://redux-toolkit.js.org/Errors?code=${e} for the full message or use the non-minified dev environment for full errors. `}i(rn,"formatProdErrorMessage");var Be=i(()=>TA(),"useAppDispatch"),me=yA,TP=Dm.withTypes();var kP="EVENTS_ADD",wH="EVENTS_RECEIVE",NP="EVENTS_TOGGLE_VISIBILITY",AP="EVENTS_TOGGLE_FILTER",pC=(h=>(h.debug="debug",h.info="info",h.web="web",h.warn="warn",h.error="error",h))(pC||{}),SH={visible:!1,filters:{debug:!1,info:!0,web:!0,warn:!0,error:!0},...ap};function hC(e=SH,t){switch(t.type){case NP:return{...e,visible:!e.visible};case AP:{let n={...e.filters,[t.filter]:!e.filters[t.filter]};return{...e,filters:n,...$u(e,km(s=>n[s.level]))}}case kP:case wH:return{...e,...$u(e,Am[t.cmd](t.data,n=>e.filters[n.level]))};default:return e}}i(hC,"reduce");function PP(e){return{type:AP,filter:e}}i(PP,"toggleFilter");function mp(){return{type:NP}}i(mp,"toggleVisibility");function LP(e,t="web"){let n={id:Math.random().toString(),message:e,level:t};return{type:kP,cmd:"add",data:n}}i(LP,"add");var OP="UI_OPTION_UPDATE_START",RP="UI_OPTION_UPDATE_SUCCESS",DP="UI_OPTION_UPDATE_ERROR",xH={};function mC(e=xH,t){switch(t.type){case OP:return{...e,[t.option]:{isUpdating:!0,value:t.value,error:!1}};case RP:return{...e,[t.option]:void 0};case DP:{let n=e[t.option].value;return typeof n=="boolean"&&(n=!n),{...e,[t.option]:{value:n,isUpdating:!1,error:t.error}}}case Yy:return{};default:return e}}i(mC,"reducer");function IP(e,t){return{type:OP,option:e,value:t}}i(IP,"startUpdate");function FP(e){return{type:RP,option:e}}i(FP,"updateSuccess");function BP(e,t){return{type:DP,option:e,error:String(t)}}i(BP,"updateError");var _H=nn({name:"ui/tabs",initialState:{current:1,isInitial:!0},reducers:{setCurrent(e,t){e.current=t.payload,e.isInitial=!1}}}),{actions:EH,reducer:bH}=_H,{setCurrent:Im}=EH,HP=bH;var zP=dp({flow:bx,modal:Yx,optionsEditor:mC,tabs:HP});var TH={state:"CONNECTION_INIT",message:void 0};function gC(e=TH,t){switch(t.type){case"CONNECTION_ESTABLISHED":case"CONNECTION_FETCHING":case"CONNECTION_ERROR":case"CONNECTION_OFFLINE":return{state:t.type,message:t.message};default:return e}}i(gC,"reducer");function UP(){return{type:"CONNECTION_FETCHING"}}i(UP,"startFetching");function WP(){return{type:"CONNECTION_ESTABLISHED"}}i(WP,"connectionEstablished");function $P(e){return{type:"CONNECTION_ERROR",message:e}}i($P,"connectionError");var VP={add_upstream_certs_to_client_chain:!1,allow_hosts:[],anticache:!1,anticomp:!1,block_global:!0,block_list:[],block_private:!1,body_size_limit:void 0,cert_passphrase:void 0,certs:[],ciphers_client:void 0,ciphers_server:void 0,client_certs:void 0,client_replay:[],client_replay_concurrency:1,command_history:!0,confdir:"~/.mitmproxy",connect_addr:void 0,connection_strategy:"eager",console_focus_follow:!1,content_view_lines_cutoff:512,dns_name_servers:[],dns_use_hosts_file:!0,export_preserve_original_ip:!1,hardump:"",http2:!0,http2_ping_keepalive:58,http3:!0,http_connect_send_host_header:!0,ignore_hosts:[],intercept:void 0,intercept_active:!1,keep_alt_svc_header:!1,keep_host_header:!1,key_size:2048,listen_host:"",listen_port:void 0,map_local:[],map_remote:[],mode:["regular"],modify_body:[],modify_headers:[],normalize_outbound_headers:!0,onboarding:!0,onboarding_host:"mitm.it",proxy_debug:!1,proxyauth:void 0,rawtcp:!0,readfile_filter:void 0,request_client_cert:!1,rfile:void 0,save_stream_file:void 0,save_stream_filter:void 0,scripts:[],server:!0,server_replay:[],server_replay_extra:"forward",server_replay_ignore_content:!1,server_replay_ignore_host:!1,server_replay_ignore_params:[],server_replay_ignore_payload_params:[],server_replay_ignore_port:!1,server_replay_kill_extra:!1,server_replay_nopop:!1,server_replay_refresh:!0,server_replay_reuse:!1,server_replay_use_headers:[],show_ignored_hosts:!1,showhost:!1,ssl_insecure:!1,ssl_verify_upstream_trusted_ca:void 0,ssl_verify_upstream_trusted_confdir:void 0,stickyauth:void 0,stickycookie:void 0,stream_large_bodies:void 0,strip_ech:!0,tcp_hosts:[],termlog_verbosity:"info",tls_ecdh_curve_client:void 0,tls_ecdh_curve_server:void 0,tls_version_client_max:"UNBOUNDED",tls_version_client_min:"TLS1_2",tls_version_server_max:"UNBOUNDED",tls_version_server_min:"TLS1_2",udp_hosts:[],upstream_auth:void 0,upstream_cert:!0,validate_inbound_headers:!0,view_filter:void 0,view_order:"time",view_order_reversed:!1,web_columns:["tls","icon","path","method","status","size","time"],web_debug:!1,web_host:"127.0.0.1",web_open_browser:!0,web_port:8081,web_static_viewer:"",websocket:!0};var vC="OPTIONS_RECEIVE",yC="OPTIONS_UPDATE";function wC(e=VP,t){switch(t.type){case vC:{let n={};for(let[s,{value:l}]of Object.entries(t.data))n[s]=l;return n}case yC:{let n={...e};for(let[s,{value:l}]of Object.entries(t.data))n[s]=l;return n}default:return e}}i(wC,"reducer");async function NH(e,t,n){try{let s=await xt.put("/options",{[e]:t});if(s.status===200)n(FP(e));else throw await s.text()}catch(s){n(BP(e,s))}}i(NH,"pureSendUpdate");var AH=NH;function gp(e,t){return n=>{n(IP(e,t)),AH(e,t,n)}}i(gp,"update");var qP="COMMANDBAR_TOGGLE_VISIBILITY",LH={visible:!1};function SC(e=LH,t){switch(t.type){case qP:return{...e,visible:!e.visible};default:return e}}i(SC,"reducer");function f0(){return{type:qP}}i(f0,"toggleVisibility");var Gn=us("STATE_RECEIVE"),Yn=us("STATE_UPDATE"),MH={available:!1,version:"",contentViews:[],servers:{},platform:""};function xC(e=MH,t){switch(t.type){case Gn.type:case Yn.type:return{...e,available:!0,...t.payload};default:return e}}i(xC,"reducer");var OH={},RH=i((e=OH,t)=>{switch(t.type){case vC:return t.data;case yC:return{...e,...t.data};default:return e}},"reducer"),KP=RH;var Xi=i((e,t)=>t.listen_host&&t.listen_port?`${e}@${t.listen_host}:${t.listen_port}`:t.listen_port?`${e}@${t.listen_port}`:e,"includeListenAddress"),d0=i(e=>{let[t,n]=Tm(e,"@");t||(t=n,n="");let[s,l]=By(t,":"),h,d;if(n){let v;if(n.includes(":")?[h,v]=Tm(n,":"):(h="",v=n),v&&(d=parseInt(v,10),isNaN(d)||d<0||d>65535))throw new Error(`invalid port: ${v}`)}return{full_spec:e,name:s,data:l,listen_host:h,listen_port:d}},"parseSpec");var p0=i(e=>Xi("regular",e),"getSpec"),CC=i(({listen_host:e,listen_port:t})=>({ui_id:Math.random(),active:!0,listen_host:e,listen_port:t}),"parseRaw");var h0=i(e=>e.selectedProcesses?`local:${e.selectedProcesses}`:"local","getSpec"),_C=i(({data:e})=>({ui_id:Math.random(),active:!0,selectedProcesses:e}),"parseRaw");var m0=i(e=>{let t=e.file_path?`wireguard:${e.file_path}`:"wireguard";return Xi(t,e)},"getSpec"),EC=i(({data:e,listen_host:t,listen_port:n})=>({ui_id:Math.random(),active:!0,listen_host:t,listen_port:n,file_path:e}),"parseRaw");var g0=(b=>(b.HTTP="http",b.HTTPS="https",b.HTTP3="http3",b.TLS="tls",b.DTLS="dtls",b.TCP="tcp",b.UDP="udp",b.DNS="dns",b.QUIC="quic",b))(g0||{});var v0=i(()=>({active:!1,protocol:"https",destination:"",ui_id:Math.random()}),"defaultReverseState"),vp=i(e=>Xi(`reverse:${e.protocol}://${e.destination}`,e),"getSpec"),GP=i(({data:e,listen_host:t,listen_port:n})=>{let[s,l]=By(e,"://");return l||(l=s,s="https"),{ui_id:Math.random(),active:!0,protocol:s,destination:l,listen_host:t,listen_port:n}},"parseRaw");var y0=i(e=>Xi("transparent",e),"getSpec"),bC=i(({listen_host:e,listen_port:t})=>({ui_id:Math.random(),active:!0,listen_host:e,listen_port:t}),"parseRaw");var w0=i(e=>Xi("socks5",e),"getSpec"),TC=i(({listen_host:e,listen_port:t})=>({ui_id:Math.random(),active:!0,listen_host:e,listen_port:t}),"parseRaw");var S0=i(e=>Xi(`upstream:${e.destination}`,e),"getSpec"),kC=i(({data:e,listen_host:t,listen_port:n})=>({ui_id:Math.random(),active:!0,destination:e||"",listen_host:t,listen_port:n}),"parseRaw");var x0=i(e=>Xi("dns",e),"getSpec"),NC=i(({listen_host:e,listen_port:t})=>({ui_id:Math.random(),active:!0,listen_host:e,listen_port:t}),"parseRaw");var qu=i(e=>e.active&&!e.error,"isActiveMode");async function DH(e,t){let n=t.getState().modes,s=[...n.regular.filter(qu).map(p0),...n.local.filter(qu).map(h0),...n.wireguard.filter(qu).map(m0),...n.reverse.filter(qu).map(vp),...n.transparent.filter(qu).map(y0),...n.socks.filter(qu).map(w0),...n.upstream.filter(qu).map(S0),...n.dns.filter(qu).map(x0)],l=await xt.put("/options",{mode:s});if(l.status!==200)throw new Error(await l.text())}i(DH,"updateModes");function Ct(e){return TP(e,DH)}i(Ct,"createModeUpdateThunk");function _t(e,t,n){e.addCase(n.pending,(s,l)=>{let{server:h,value:d}=l.meta.arg,v=s.findIndex(S=>S.ui_id===h.ui_id);v>=0&&(s[v][t]=d,s[v].error=void 0)}),e.addCase(n.rejected,(s,l)=>{let{server:h}=l.meta.arg,d=s.findIndex(v=>v.ui_id===h.ui_id);d>=0&&(s[d].error=l.error.message)})}i(_t,"addSetter");function Vr(e,t){return i(function(s,l){if(l.payload.servers){let h=Object.values(l.payload.servers).filter(d=>d.type===e).map(d=>d0(d.full_spec));if(h.length>0)return h.map(t);for(let d of s)d.active=!1}},"reducer")}i(Vr,"updateState");var AC=Ct("modes/regular/setActive"),PC=Ct("modes/regular/setListenHost"),LC=Ct("modes/regular/setListenPort"),IH=[{active:!0,ui_id:Math.random()}],FH=nn({name:"modes/regular",initialState:IH,reducers:{},extraReducers:i(e=>{_t(e,"active",AC),_t(e,"listen_host",PC),_t(e,"listen_port",LC),e.addCase(Gn,Vr("regular",CC)),e.addCase(Yn,Vr("regular",CC))},"extraReducers")}),YP=FH.reducer;var MC=Ct("modes/local/setActive"),yp=Ct("modes/local/setSelectedProcesses"),BH=[{active:!1,selectedProcesses:"",ui_id:Math.random()}],HH=nn({name:"modes/local",initialState:BH,reducers:{},extraReducers:i(e=>{_t(e,"active",MC),_t(e,"selectedProcesses",yp),e.addCase(Gn,Vr("local",_C)),e.addCase(Yn,Vr("local",_C))},"extraReducers")}),XP=HH.reducer;var OC=Ct("modes/wireguard/setActive"),RC=Ct("modes/wireguard/setListenHost"),DC=Ct("modes/wireguard/setListenPort"),IC=Ct("modes/wireguard/setFilePath"),zH=[{active:!1,ui_id:Math.random()}],UH=nn({name:"modes/wireguard",initialState:zH,reducers:{},extraReducers:i(e=>{_t(e,"active",OC),_t(e,"listen_host",RC),_t(e,"listen_port",DC),_t(e,"file_path",IC),e.addCase(Gn,Vr("wireguard",EC)),e.addCase(Yn,Vr("wireguard",EC))},"extraReducers")}),QP=UH.reducer;var C0=Ct("modes/reverse/setActive"),FC=Ct("modes/reverse/setListenHost"),BC=Ct("modes/reverse/setListenPort"),HC=Ct("modes/reverse/setProtocol"),zC=Ct("modes/reverse/setDestination"),WH=[v0()],JP=nn({name:"modes/reverse",initialState:WH,reducers:{addServer:i(e=>{e.push(v0())},"addServer"),removeServer:i((e,t)=>{let n=e.findIndex(s=>s.ui_id===t.payload.ui_id);n!==-1&&(e[n].active&&console.error("servers should be deactivated before removal"),e.splice(n,1))},"removeServer")},extraReducers:i(e=>{_t(e,"active",C0),_t(e,"listen_host",FC),_t(e,"listen_port",BC),_t(e,"protocol",HC),_t(e,"destination",zC),e.addCase(Gn,t),e.addCase(Yn,t);function t(n,s){if(s.payload.servers){let l=Object.fromEntries(Object.entries(s.payload.servers).filter(([d,v])=>v.type==="reverse").map(([d,v])=>[d,d0(d)])),h=[];for(let d of n){let v=vp(d),S=v in l;delete l[v],h.push({...d,active:S})}for(let d of Object.values(l))h.push(GP(d));return h.length>1&&Mo({...h[0],ui_id:void 0},{...v0(),ui_id:void 0})&&h.shift(),h}}i(t,"updateState")},"extraReducers")}),{addServer:ZP,removeServer:eL}=JP.actions,tL=JP.reducer;var UC=Ct("modes/transparent/setActive"),WC=Ct("modes/transparent/setListenHost"),$C=Ct("modes/transparent/setListenPort"),$H=[{active:!1,ui_id:Math.random()}],VH=nn({name:"modes/transparent",initialState:$H,reducers:{},extraReducers:i(e=>{_t(e,"active",UC),_t(e,"listen_host",WC),_t(e,"listen_port",$C),e.addCase(Gn,Vr("transparent",bC)),e.addCase(Yn,Vr("transparent",bC))},"extraReducers")}),rL=VH.reducer;var VC=Ct("modes/socks5/setActive"),qC=Ct("modes/socks5/setListenHost"),jC=Ct("modes/socks5/setListenPort"),qH=[{active:!1,ui_id:Math.random()}],jH=nn({name:"modes/socks5",initialState:qH,reducers:{},extraReducers:i(e=>{_t(e,"active",VC),_t(e,"listen_host",qC),_t(e,"listen_port",jC),e.addCase(Gn,Vr("socks5",TC)),e.addCase(Yn,Vr("socks5",TC))},"extraReducers")}),nL=jH.reducer;var KC=Ct("modes/upstream/setActive"),GC=Ct("modes/upstream/setListenHost"),YC=Ct("modes/upstream/setListenPort"),XC=Ct("modes/upstream/setDestination"),KH=[{active:!1,destination:"",ui_id:Math.random()}],GH=nn({name:"modes/upstream",initialState:KH,reducers:{},extraReducers:i(e=>{_t(e,"active",KC),_t(e,"listen_host",GC),_t(e,"listen_port",YC),_t(e,"destination",XC),e.addCase(Gn,Vr("upstream",kC)),e.addCase(Yn,Vr("upstream",kC))},"extraReducers")}),iL=GH.reducer;var QC=Ct("modes/dns/setActive"),JC=Ct("modes/dns/setListenHost"),ZC=Ct("modes/dns/setListenPort"),YH=[{active:!0,ui_id:Math.random()}],XH=nn({name:"modes/dns",initialState:YH,reducers:{},extraReducers:i(e=>{_t(e,"active",QC),_t(e,"listen_host",JC),_t(e,"listen_port",ZC),e.addCase(Gn,Vr("dns",NC)),e.addCase(Yn,Vr("dns",NC))},"extraReducers")}),oL=XH.reducer;var QH=dp({regular:YP,local:XP,wireguard:QP,reverse:tL,transparent:rL,socks:nL,upstream:iL,dns:oL}),sL=QH;var Cf=Dm("fetchProcesses",async(e,{rejectWithValue:t})=>{try{return(await xt("/processes")).json()}catch(n){return t(n.message)}}),JH={currentProcesses:[],isLoading:!1},ZH=nn({name:"processes",initialState:JH,reducers:{},extraReducers:i(e=>{e.addCase(Cf.pending,t=>{t.isLoading=!0,t.error=void 0}),e.addCase(Cf.fulfilled,(t,n)=>{t.isLoading=!1,t.currentProcesses=n.payload}),e.addCase(Cf.rejected,(t,n)=>{t.isLoading=!1,t.error=n.payload})},"extraReducers")}),aL=ZH.reducer;var ez={commandBar:SC,eventLog:hC,flows:Gx,connection:gC,modes:sL,ui:zP,options:wC,options_meta:KP,backendState:xC,processes:aL},_f=wP({reducer:ez,middleware:i(e=>e({immutableCheck:{warnAfter:5e5},serializableCheck:{warnAfter:5e5}}),"middleware")});var Io=pe(Te());var lL=pe(bm()),uL=pe(ai());var e_=class extends Io.Component{constructor(){super(...arguments);this.container=Io.default.createRef();this.nameInput=Io.default.createRef();this.valueInput=Io.default.createRef();this.render=i(()=>{let[n,s]=this.props.item;return Io.default.createElement("div",{ref:this.container,className:"kv-row",onClick:this.onClick,onKeyDownCapture:this.onKeyDown},Io.default.createElement(gt,{ref:this.nameInput,className:"kv-key",content:n,onEditStart:this.props.onEditStart,onEditDone:l=>this.props.onEditDone([l,s])}),":\xA0",Io.default.createElement(gt,{ref:this.valueInput,className:"kv-value",content:s,onEditStart:this.props.onEditStart,onEditDone:l=>this.props.onEditDone([n,l]),placeholder:"empty"}))},"render");this.onClick=i(n=>{n.target===this.container.current&&this.props.onClickEmptyArea()},"onClick");this.onKeyDown=i(n=>{n.target===this.valueInput.current?.input.current&&n.key==="Tab"&&this.props.onTabNext()},"onKeyDown")}static{i(this,"Row")}},wp=class extends Io.Component{constructor(){super(...arguments);this.rowRefs={};this.state={currentList:this.props.data||[],initialList:this.props.data};this.render=i(()=>{this.rowRefs={};let n=this.state.currentList.map((s,l)=>Io.default.createElement(e_,{key:l,item:s,onEditStart:()=>this.currentlyEditing=l,onEditDone:h=>this.onEditDone(l,h),onClickEmptyArea:()=>this.onClickEmptyArea(l),onTabNext:()=>this.onTabNext(l),ref:h=>this.rowRefs[l]=h}));return Io.default.createElement("div",{className:(0,uL.default)("kv-editor",this.props.className),onMouseDown:this.onMouseDown},n,Io.default.createElement("div",{onClick:s=>{s.preventDefault(),this.onClickEmptyArea(this.state.currentList.length-1)},className:"kv-add-row fa fa-plus-square-o",role:"button","aria-label":"Add"}))},"render");this.onEditDone=i((n,s)=>{let l=[...this.state.currentList];s[0]?l[n]=s:l.splice(n,1),this.currentlyEditing=void 0,(0,lL.isEqual)(this.state.currentList,l)||this.props.onChange(l),this.setState({currentList:l})},"onEditDone");this.onClickEmptyArea=i(n=>{if(this.justFinishedEditing)return;let s=[...this.state.currentList];s.splice(n+1,0,["",""]),this.setState({currentList:s},()=>this.rowRefs[n+1]?.nameInput.current?.startEditing())},"onClickEmptyArea");this.onTabNext=i(n=>{n==this.state.currentList.length-1&&this.onClickEmptyArea(n)},"onTabNext");this.onMouseDown=i(n=>{this.justFinishedEditing=this.currentlyEditing},"onMouseDown")}static{i(this,"KeyValueListEditor")}static getDerivedStateFromProps(n,s){return n.data!==s.initialList?{currentList:n.data||[],initialList:n.data}:null}};var nr=pe(Te());var Fm=pe(Te());function _0(e,t){let[n,s]=(0,Fm.useState)(),[l,h]=(0,Fm.useState)();return(0,Fm.useEffect)(()=>{l&&l.abort();let d=new AbortController;return xt(e,{signal:d.signal}).then(v=>{if(!v.ok)throw`${v.status} ${v.statusText}`.trim();return v.text()}).then(v=>{s(v)}).catch(v=>{d.signal.aborted||s(`Error getting content: ${v}.`)}),h(d),()=>{d.signal.aborted||d.abort()}},[e,t]),n}i(_0,"useContent");var Bm=pe(Te());var E0=Bm.default.memo(i(function({icon:t,text:n,className:s,title:l,onOpenFile:h,onClick:d}){let v;return Bm.default.createElement("a",{href:"#",onClick:S=>{v.click(),d&&d(S)},className:s,title:l},Bm.default.createElement("i",{className:"fa fa-fw "+t}),n,Bm.default.createElement("input",{ref:S=>v=S,className:"hidden",type:"file",onChange:S=>{S.preventDefault(),S.target.files&&S.target.files.length>0&&h(S.target.files[0]),v.value=""}}))},"FileChooser"));var Sp=pe(Te()),cL=pe(ai());function Or({onClick:e,children:t,icon:n,disabled:s,className:l,title:h}){return Sp.createElement("button",{className:(0,cL.default)(l,"btn btn-default"),onClick:s?void 0:e,disabled:s,title:h},n&&Sp.createElement(Sp.Fragment,null,Sp.createElement("i",{className:"fa "+n}),"\xA0"),t)}i(Or,"Button");var Um=pe(Te()),gL=pe(Te());var Hm=pe(Te()),pL=pe(ai()),hL=pe(fL()),mL=pe(bm());function dL(e){return e&&e.replace(/\r\n|\r/g,` +`)}i(dL,"normalizeLineEndings");var zm=class extends Hm.Component{static{i(this,"CodeMirror")}constructor(t){super(t),this.state={isFocused:!1}}static{this.defaultProps={preserveScrollPosition:!1}}getCodeMirrorInstance(){return this.props.codeMirrorInstance||hL.default}UNSAFE_componentWillMount(){this.props.path&&console.error("Warning: react-codemirror: the `path` prop has been changed to `name`")}componentDidMount(){let t=this.getCodeMirrorInstance();this.codeMirror=t.fromTextArea(this.textareaNode,this.props.options),this.codeMirror.on("change",this.codemirrorValueChanged.bind(this)),this.codeMirror.on("cursorActivity",this.cursorActivity.bind(this)),this.codeMirror.on("focus",this.focusChanged.bind(this,!0)),this.codeMirror.on("blur",this.focusChanged.bind(this,!1)),this.codeMirror.on("scroll",this.scrollChanged.bind(this)),this.codeMirror.setValue(this.props.defaultValue||this.props.value||"")}componentWillUnmount(){this.codeMirror&&this.codeMirror.toTextArea()}UNSAFE_componentWillReceiveProps(t){if(this.codeMirror&&t.value!==void 0&&t.value!==this.props.value&&dL(this.codeMirror.getValue())!==dL(t.value))if(this.props.preserveScrollPosition){let n=this.codeMirror.getScrollInfo();this.codeMirror.setValue(t.value),this.codeMirror.scrollTo(n.left,n.top)}else this.codeMirror.setValue(t.value);if(typeof t.options=="object")for(let n in t.options)t.options.hasOwnProperty(n)&&this.setOptionIfChanged(n,t.options[n])}setOptionIfChanged(t,n){let s=this.codeMirror.getOption(t);(0,mL.isEqual)(s,n)||this.codeMirror.setOption(t,n)}getCodeMirror(){return this.codeMirror}focus(){this.codeMirror&&this.codeMirror.focus()}focusChanged(t){this.setState({isFocused:t}),this.props.onFocusChange&&this.props.onFocusChange(t)}cursorActivity(t){this.props.onCursorActivity&&this.props.onCursorActivity(t)}scrollChanged(t){this.props.onScroll&&this.props.onScroll(t.getScrollInfo())}codemirrorValueChanged(t,n){this.props.onChange&&n.origin!=="setValue"&&this.props.onChange(t.getValue(),n)}render(){let t=(0,pL.default)("ReactCodeMirror",this.state.isFocused?"ReactCodeMirror--focused":null,this.props.className);return Hm.createElement("div",{className:t},Hm.createElement("textarea",{ref:n=>this.textareaNode=n,name:this.props.name||this.props.path,defaultValue:this.props.value,autoComplete:"off",autoFocus:this.props.autoFocus}))}};var Wm=class extends gL.Component{constructor(){super(...arguments);this.editor=Um.createRef();this.getContent=i(()=>this.editor.current?.codeMirror.getValue(),"getContent");this.render=i(()=>{let n={lineNumbers:!0};return Um.createElement("div",{className:"codeeditor",onKeyDown:s=>s.stopPropagation()},Um.createElement(zm,{ref:this.editor,value:this.props.initialContent,onChange:()=>0,options:n}))},"render")}static{i(this,"CodeEditor")}};var Ef=pe(Te());var tz=Ef.default.memo(i(function({lines:t,maxLines:n,showMore:s}){return t.length===0?null:Ef.default.createElement("pre",null,t.map((l,h)=>h===n?Ef.default.createElement("button",{key:"showmore",onClick:s,className:"btn btn-xs btn-info"},Ef.default.createElement("i",{className:"fa fa-angle-double-down","aria-hidden":"true"})," ","Show more"):Ef.default.createElement("div",{key:h},l.map(([d,v],S)=>Ef.default.createElement("span",{key:S,className:d},v)))))},"LineRenderer")),b0=tz;var Of=pe(Te());var Ni=pe(Te());var T0=pe(Te());var n_=i(function(t){return t.reduce(function(n,s){var l=s[0],h=s[1];return n[l]=h,n},{})},"fromEntries"),i_=typeof window<"u"&&window.document&&window.document.createElement?T0.useLayoutEffect:T0.useEffect;var Gu=pe(Te()),zL=pe(yx());var Rr="top",xn="bottom",on="right",qr="left",k0="auto",ju=[Rr,xn,on,qr],Sl="start",bf="end",vL="clippingParents",N0="viewport",xp="popper",yL="reference",o_=ju.reduce(function(e,t){return e.concat([t+"-"+Sl,t+"-"+bf])},[]),A0=[].concat(ju,[k0]).reduce(function(e,t){return e.concat([t,t+"-"+Sl,t+"-"+bf])},[]),rz="beforeRead",nz="read",iz="afterRead",oz="beforeMain",sz="main",az="afterMain",lz="beforeWrite",uz="write",cz="afterWrite",wL=[rz,nz,iz,oz,sz,az,lz,uz,cz];function Rn(e){return e?(e.nodeName||"").toLowerCase():null}i(Rn,"getNodeName");function mr(e){if(e==null)return window;if(e.toString()!=="[object Window]"){var t=e.ownerDocument;return t&&t.defaultView||window}return e}i(mr,"getWindow");function cs(e){var t=mr(e).Element;return e instanceof t||e instanceof Element}i(cs,"isElement");function Cn(e){var t=mr(e).HTMLElement;return e instanceof t||e instanceof HTMLElement}i(Cn,"isHTMLElement");function Cp(e){if(typeof ShadowRoot>"u")return!1;var t=mr(e).ShadowRoot;return e instanceof t||e instanceof ShadowRoot}i(Cp,"isShadowRoot");function fz(e){var t=e.state;Object.keys(t.elements).forEach(function(n){var s=t.styles[n]||{},l=t.attributes[n]||{},h=t.elements[n];!Cn(h)||!Rn(h)||(Object.assign(h.style,s),Object.keys(l).forEach(function(d){var v=l[d];v===!1?h.removeAttribute(d):h.setAttribute(d,v===!0?"":v)}))})}i(fz,"applyStyles");function dz(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach(function(s){var l=t.elements[s],h=t.attributes[s]||{},d=Object.keys(t.styles.hasOwnProperty(s)?t.styles[s]:n[s]),v=d.reduce(function(S,b){return S[b]="",S},{});!Cn(l)||!Rn(l)||(Object.assign(l.style,v),Object.keys(h).forEach(function(S){l.removeAttribute(S)}))})}}i(dz,"effect");var SL={name:"applyStyles",enabled:!0,phase:"write",fn:fz,effect:dz,requires:["computeStyles"]};function Dn(e){return e.split("-")[0]}i(Dn,"getBasePlacement");var Us=Math.max,Tf=Math.min,xl=Math.round;function _p(){var e=navigator.userAgentData;return e!=null&&e.brands&&Array.isArray(e.brands)?e.brands.map(function(t){return t.brand+"/"+t.version}).join(" "):navigator.userAgent}i(_p,"getUAString");function $m(){return!/^((?!chrome|android).)*safari/i.test(_p())}i($m,"isLayoutViewport");function fs(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!1);var s=e.getBoundingClientRect(),l=1,h=1;t&&Cn(e)&&(l=e.offsetWidth>0&&xl(s.width)/e.offsetWidth||1,h=e.offsetHeight>0&&xl(s.height)/e.offsetHeight||1);var d=cs(e)?mr(e):window,v=d.visualViewport,S=!$m()&&n,b=(s.left+(S&&v?v.offsetLeft:0))/l,k=(s.top+(S&&v?v.offsetTop:0))/h,R=s.width/l,I=s.height/h;return{width:R,height:I,top:k,right:b+R,bottom:k+I,left:b,x:b,y:k}}i(fs,"getBoundingClientRect");function kf(e){var t=fs(e),n=e.offsetWidth,s=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-s)<=1&&(s=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:s}}i(kf,"getLayoutRect");function Vm(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&Cp(n)){var s=t;do{if(s&&e.isSameNode(s))return!0;s=s.parentNode||s.host}while(s)}return!1}i(Vm,"contains");function ki(e){return mr(e).getComputedStyle(e)}i(ki,"getComputedStyle");function s_(e){return["table","td","th"].indexOf(Rn(e))>=0}i(s_,"isTableElement");function Xn(e){return((cs(e)?e.ownerDocument:e.document)||window.document).documentElement}i(Xn,"getDocumentElement");function Cl(e){return Rn(e)==="html"?e:e.assignedSlot||e.parentNode||(Cp(e)?e.host:null)||Xn(e)}i(Cl,"getParentNode");function xL(e){return!Cn(e)||ki(e).position==="fixed"?null:e.offsetParent}i(xL,"getTrueOffsetParent");function pz(e){var t=/firefox/i.test(_p()),n=/Trident/i.test(_p());if(n&&Cn(e)){var s=ki(e);if(s.position==="fixed")return null}var l=Cl(e);for(Cp(l)&&(l=l.host);Cn(l)&&["html","body"].indexOf(Rn(l))<0;){var h=ki(l);if(h.transform!=="none"||h.perspective!=="none"||h.contain==="paint"||["transform","perspective"].indexOf(h.willChange)!==-1||t&&h.willChange==="filter"||t&&h.filter&&h.filter!=="none")return l;l=l.parentNode}return null}i(pz,"getContainingBlock");function Ws(e){for(var t=mr(e),n=xL(e);n&&s_(n)&&ki(n).position==="static";)n=xL(n);return n&&(Rn(n)==="html"||Rn(n)==="body"&&ki(n).position==="static")?t:n||pz(e)||t}i(Ws,"getOffsetParent");function Nf(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}i(Nf,"getMainAxisFromPlacement");function Af(e,t,n){return Us(e,Tf(t,n))}i(Af,"within");function CL(e,t,n){var s=Af(e,t,n);return s>n?n:s}i(CL,"withinMaxClamp");function qm(){return{top:0,right:0,bottom:0,left:0}}i(qm,"getFreshSideObject");function jm(e){return Object.assign({},qm(),e)}i(jm,"mergePaddingObject");function Km(e,t){return t.reduce(function(n,s){return n[s]=e,n},{})}i(Km,"expandToHashMap");var hz=i(function(t,n){return t=typeof t=="function"?t(Object.assign({},n.rects,{placement:n.placement})):t,jm(typeof t!="number"?t:Km(t,ju))},"toPaddingObject");function mz(e){var t,n=e.state,s=e.name,l=e.options,h=n.elements.arrow,d=n.modifiersData.popperOffsets,v=Dn(n.placement),S=Nf(v),b=[qr,on].indexOf(v)>=0,k=b?"height":"width";if(!(!h||!d)){var R=hz(l.padding,n),I=kf(h),z=S==="y"?Rr:qr,q=S==="y"?xn:on,Q=n.rects.reference[k]+n.rects.reference[S]-d[S]-n.rects.popper[k],ne=d[S]-n.rects.reference[S],D=Ws(h),L=D?S==="y"?D.clientHeight||0:D.clientWidth||0:0,B=Q/2-ne/2,j=R[z],re=L-I[k]-R[q],Z=L/2-I[k]/2+B,oe=Af(j,Z,re),he=S;n.modifiersData[s]=(t={},t[he]=oe,t.centerOffset=oe-Z,t)}}i(mz,"arrow");function gz(e){var t=e.state,n=e.options,s=n.element,l=s===void 0?"[data-popper-arrow]":s;l!=null&&(typeof l=="string"&&(l=t.elements.popper.querySelector(l),!l)||Vm(t.elements.popper,l)&&(t.elements.arrow=l))}i(gz,"effect");var _L={name:"arrow",enabled:!0,phase:"main",fn:mz,effect:gz,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ds(e){return e.split("-")[1]}i(ds,"getVariation");var vz={top:"auto",right:"auto",bottom:"auto",left:"auto"};function yz(e,t){var n=e.x,s=e.y,l=t.devicePixelRatio||1;return{x:xl(n*l)/l||0,y:xl(s*l)/l||0}}i(yz,"roundOffsetsByDPR");function EL(e){var t,n=e.popper,s=e.popperRect,l=e.placement,h=e.variation,d=e.offsets,v=e.position,S=e.gpuAcceleration,b=e.adaptive,k=e.roundOffsets,R=e.isFixed,I=d.x,z=I===void 0?0:I,q=d.y,Q=q===void 0?0:q,ne=typeof k=="function"?k({x:z,y:Q}):{x:z,y:Q};z=ne.x,Q=ne.y;var D=d.hasOwnProperty("x"),L=d.hasOwnProperty("y"),B=qr,j=Rr,re=window;if(b){var Z=Ws(n),oe="clientHeight",he="clientWidth";if(Z===mr(n)&&(Z=Xn(n),ki(Z).position!=="static"&&v==="absolute"&&(oe="scrollHeight",he="scrollWidth")),Z=Z,l===Rr||(l===qr||l===on)&&h===bf){j=xn;var Re=R&&Z===re&&re.visualViewport?re.visualViewport.height:Z[oe];Q-=Re-s.height,Q*=S?1:-1}if(l===qr||(l===Rr||l===xn)&&h===bf){B=on;var Ee=R&&Z===re&&re.visualViewport?re.visualViewport.width:Z[he];z-=Ee-s.width,z*=S?1:-1}}var Ye=Object.assign({position:v},b&&vz),tt=k===!0?yz({x:z,y:Q},mr(n)):{x:z,y:Q};if(z=tt.x,Q=tt.y,S){var xe;return Object.assign({},Ye,(xe={},xe[j]=L?"0":"",xe[B]=D?"0":"",xe.transform=(re.devicePixelRatio||1)<=1?"translate("+z+"px, "+Q+"px)":"translate3d("+z+"px, "+Q+"px, 0)",xe))}return Object.assign({},Ye,(t={},t[j]=L?Q+"px":"",t[B]=D?z+"px":"",t.transform="",t))}i(EL,"mapToStyles");function wz(e){var t=e.state,n=e.options,s=n.gpuAcceleration,l=s===void 0?!0:s,h=n.adaptive,d=h===void 0?!0:h,v=n.roundOffsets,S=v===void 0?!0:v,b={placement:Dn(t.placement),variation:ds(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:l,isFixed:t.options.strategy==="fixed"};t.modifiersData.popperOffsets!=null&&(t.styles.popper=Object.assign({},t.styles.popper,EL(Object.assign({},b,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:d,roundOffsets:S})))),t.modifiersData.arrow!=null&&(t.styles.arrow=Object.assign({},t.styles.arrow,EL(Object.assign({},b,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:S})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})}i(wz,"computeStyles");var bL={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:wz,data:{}};var P0={passive:!0};function Sz(e){var t=e.state,n=e.instance,s=e.options,l=s.scroll,h=l===void 0?!0:l,d=s.resize,v=d===void 0?!0:d,S=mr(t.elements.popper),b=[].concat(t.scrollParents.reference,t.scrollParents.popper);return h&&b.forEach(function(k){k.addEventListener("scroll",n.update,P0)}),v&&S.addEventListener("resize",n.update,P0),function(){h&&b.forEach(function(k){k.removeEventListener("scroll",n.update,P0)}),v&&S.removeEventListener("resize",n.update,P0)}}i(Sz,"effect");var TL={name:"eventListeners",enabled:!0,phase:"write",fn:i(function(){},"fn"),effect:Sz,data:{}};var xz={left:"right",right:"left",bottom:"top",top:"bottom"};function Ep(e){return e.replace(/left|right|bottom|top/g,function(t){return xz[t]})}i(Ep,"getOppositePlacement");var Cz={start:"end",end:"start"};function L0(e){return e.replace(/start|end/g,function(t){return Cz[t]})}i(L0,"getOppositeVariationPlacement");function Pf(e){var t=mr(e),n=t.pageXOffset,s=t.pageYOffset;return{scrollLeft:n,scrollTop:s}}i(Pf,"getWindowScroll");function Lf(e){return fs(Xn(e)).left+Pf(e).scrollLeft}i(Lf,"getWindowScrollBarX");function a_(e,t){var n=mr(e),s=Xn(e),l=n.visualViewport,h=s.clientWidth,d=s.clientHeight,v=0,S=0;if(l){h=l.width,d=l.height;var b=$m();(b||!b&&t==="fixed")&&(v=l.offsetLeft,S=l.offsetTop)}return{width:h,height:d,x:v+Lf(e),y:S}}i(a_,"getViewportRect");function l_(e){var t,n=Xn(e),s=Pf(e),l=(t=e.ownerDocument)==null?void 0:t.body,h=Us(n.scrollWidth,n.clientWidth,l?l.scrollWidth:0,l?l.clientWidth:0),d=Us(n.scrollHeight,n.clientHeight,l?l.scrollHeight:0,l?l.clientHeight:0),v=-s.scrollLeft+Lf(e),S=-s.scrollTop;return ki(l||n).direction==="rtl"&&(v+=Us(n.clientWidth,l?l.clientWidth:0)-h),{width:h,height:d,x:v,y:S}}i(l_,"getDocumentRect");function Mf(e){var t=ki(e),n=t.overflow,s=t.overflowX,l=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+l+s)}i(Mf,"isScrollParent");function M0(e){return["html","body","#document"].indexOf(Rn(e))>=0?e.ownerDocument.body:Cn(e)&&Mf(e)?e:M0(Cl(e))}i(M0,"getScrollParent");function Ku(e,t){var n;t===void 0&&(t=[]);var s=M0(e),l=s===((n=e.ownerDocument)==null?void 0:n.body),h=mr(s),d=l?[h].concat(h.visualViewport||[],Mf(s)?s:[]):s,v=t.concat(d);return l?v:v.concat(Ku(Cl(d)))}i(Ku,"listScrollParents");function bp(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}i(bp,"rectToClientRect");function _z(e,t){var n=fs(e,!1,t==="fixed");return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}i(_z,"getInnerBoundingClientRect");function kL(e,t,n){return t===N0?bp(a_(e,n)):cs(t)?_z(t,n):bp(l_(Xn(e)))}i(kL,"getClientRectFromMixedType");function Ez(e){var t=Ku(Cl(e)),n=["absolute","fixed"].indexOf(ki(e).position)>=0,s=n&&Cn(e)?Ws(e):e;return cs(s)?t.filter(function(l){return cs(l)&&Vm(l,s)&&Rn(l)!=="body"}):[]}i(Ez,"getClippingParents");function u_(e,t,n,s){var l=t==="clippingParents"?Ez(e):[].concat(t),h=[].concat(l,[n]),d=h[0],v=h.reduce(function(S,b){var k=kL(e,b,s);return S.top=Us(k.top,S.top),S.right=Tf(k.right,S.right),S.bottom=Tf(k.bottom,S.bottom),S.left=Us(k.left,S.left),S},kL(e,d,s));return v.width=v.right-v.left,v.height=v.bottom-v.top,v.x=v.left,v.y=v.top,v}i(u_,"getClippingRect");function Gm(e){var t=e.reference,n=e.element,s=e.placement,l=s?Dn(s):null,h=s?ds(s):null,d=t.x+t.width/2-n.width/2,v=t.y+t.height/2-n.height/2,S;switch(l){case Rr:S={x:d,y:t.y-n.height};break;case xn:S={x:d,y:t.y+t.height};break;case on:S={x:t.x+t.width,y:v};break;case qr:S={x:t.x-n.width,y:v};break;default:S={x:t.x,y:t.y}}var b=l?Nf(l):null;if(b!=null){var k=b==="y"?"height":"width";switch(h){case Sl:S[b]=S[b]-(t[k]/2-n[k]/2);break;case bf:S[b]=S[b]+(t[k]/2-n[k]/2);break;default:}}return S}i(Gm,"computeOffsets");function $s(e,t){t===void 0&&(t={});var n=t,s=n.placement,l=s===void 0?e.placement:s,h=n.strategy,d=h===void 0?e.strategy:h,v=n.boundary,S=v===void 0?vL:v,b=n.rootBoundary,k=b===void 0?N0:b,R=n.elementContext,I=R===void 0?xp:R,z=n.altBoundary,q=z===void 0?!1:z,Q=n.padding,ne=Q===void 0?0:Q,D=jm(typeof ne!="number"?ne:Km(ne,ju)),L=I===xp?yL:xp,B=e.rects.popper,j=e.elements[q?L:I],re=u_(cs(j)?j:j.contextElement||Xn(e.elements.popper),S,k,d),Z=fs(e.elements.reference),oe=Gm({reference:Z,element:B,strategy:"absolute",placement:l}),he=bp(Object.assign({},B,oe)),Re=I===xp?he:Z,Ee={top:re.top-Re.top+D.top,bottom:Re.bottom-re.bottom+D.bottom,left:re.left-Re.left+D.left,right:Re.right-re.right+D.right},Ye=e.modifiersData.offset;if(I===xp&&Ye){var tt=Ye[l];Object.keys(Ee).forEach(function(xe){var Xe=[on,xn].indexOf(xe)>=0?1:-1,je=[Rr,xn].indexOf(xe)>=0?"y":"x";Ee[xe]+=tt[je]*Xe})}return Ee}i($s,"detectOverflow");function c_(e,t){t===void 0&&(t={});var n=t,s=n.placement,l=n.boundary,h=n.rootBoundary,d=n.padding,v=n.flipVariations,S=n.allowedAutoPlacements,b=S===void 0?A0:S,k=ds(s),R=k?v?o_:o_.filter(function(q){return ds(q)===k}):ju,I=R.filter(function(q){return b.indexOf(q)>=0});I.length===0&&(I=R);var z=I.reduce(function(q,Q){return q[Q]=$s(e,{placement:Q,boundary:l,rootBoundary:h,padding:d})[Dn(Q)],q},{});return Object.keys(z).sort(function(q,Q){return z[q]-z[Q]})}i(c_,"computeAutoPlacement");function bz(e){if(Dn(e)===k0)return[];var t=Ep(e);return[L0(e),t,L0(t)]}i(bz,"getExpandedFallbackPlacements");function Tz(e){var t=e.state,n=e.options,s=e.name;if(!t.modifiersData[s]._skip){for(var l=n.mainAxis,h=l===void 0?!0:l,d=n.altAxis,v=d===void 0?!0:d,S=n.fallbackPlacements,b=n.padding,k=n.boundary,R=n.rootBoundary,I=n.altBoundary,z=n.flipVariations,q=z===void 0?!0:z,Q=n.allowedAutoPlacements,ne=t.options.placement,D=Dn(ne),L=D===ne,B=S||(L||!q?[Ep(ne)]:bz(ne)),j=[ne].concat(B).reduce(function(vr,yr){return vr.concat(Dn(yr)===k0?c_(t,{placement:yr,boundary:k,rootBoundary:R,padding:b,flipVariations:q,allowedAutoPlacements:Q}):yr)},[]),re=t.rects.reference,Z=t.rects.popper,oe=new Map,he=!0,Re=j[0],Ee=0;Ee=0,je=Xe?"width":"height",Qe=$s(t,{placement:Ye,boundary:k,rootBoundary:R,altBoundary:I,padding:b}),ot=Xe?xe?on:qr:xe?xn:Rr;re[je]>Z[je]&&(ot=Ep(ot));var It=Ep(ot),At=[];if(h&&At.push(Qe[tt]<=0),v&&At.push(Qe[ot]<=0,Qe[It]<=0),At.every(function(vr){return vr})){Re=Ye,he=!1;break}oe.set(Ye,At)}if(he)for(var cn=q?3:1,fn=i(function(yr){var Gt=j.find(function(Ft){var se=oe.get(Ft);if(se)return se.slice(0,yr).every(function(Ue){return Ue})});if(Gt)return Re=Gt,"break"},"_loop"),gr=cn;gr>0;gr--){var Wt=fn(gr);if(Wt==="break")break}t.placement!==Re&&(t.modifiersData[s]._skip=!0,t.placement=Re,t.reset=!0)}}i(Tz,"flip");var NL={name:"flip",enabled:!0,phase:"main",fn:Tz,requiresIfExists:["offset"],data:{_skip:!1}};function AL(e,t,n){return n===void 0&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}i(AL,"getSideOffsets");function PL(e){return[Rr,on,xn,qr].some(function(t){return e[t]>=0})}i(PL,"isAnySideFullyClipped");function kz(e){var t=e.state,n=e.name,s=t.rects.reference,l=t.rects.popper,h=t.modifiersData.preventOverflow,d=$s(t,{elementContext:"reference"}),v=$s(t,{altBoundary:!0}),S=AL(d,s),b=AL(v,l,h),k=PL(S),R=PL(b);t.modifiersData[n]={referenceClippingOffsets:S,popperEscapeOffsets:b,isReferenceHidden:k,hasPopperEscaped:R},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":k,"data-popper-escaped":R})}i(kz,"hide");var LL={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:kz};function Nz(e,t,n){var s=Dn(e),l=[qr,Rr].indexOf(s)>=0?-1:1,h=typeof n=="function"?n(Object.assign({},t,{placement:e})):n,d=h[0],v=h[1];return d=d||0,v=(v||0)*l,[qr,on].indexOf(s)>=0?{x:v,y:d}:{x:d,y:v}}i(Nz,"distanceAndSkiddingToXY");function Az(e){var t=e.state,n=e.options,s=e.name,l=n.offset,h=l===void 0?[0,0]:l,d=A0.reduce(function(k,R){return k[R]=Nz(R,t.rects,h),k},{}),v=d[t.placement],S=v.x,b=v.y;t.modifiersData.popperOffsets!=null&&(t.modifiersData.popperOffsets.x+=S,t.modifiersData.popperOffsets.y+=b),t.modifiersData[s]=d}i(Az,"offset");var ML={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:Az};function Pz(e){var t=e.state,n=e.name;t.modifiersData[n]=Gm({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})}i(Pz,"popperOffsets");var OL={name:"popperOffsets",enabled:!0,phase:"read",fn:Pz,data:{}};function f_(e){return e==="x"?"y":"x"}i(f_,"getAltAxis");function Lz(e){var t=e.state,n=e.options,s=e.name,l=n.mainAxis,h=l===void 0?!0:l,d=n.altAxis,v=d===void 0?!1:d,S=n.boundary,b=n.rootBoundary,k=n.altBoundary,R=n.padding,I=n.tether,z=I===void 0?!0:I,q=n.tetherOffset,Q=q===void 0?0:q,ne=$s(t,{boundary:S,rootBoundary:b,padding:R,altBoundary:k}),D=Dn(t.placement),L=ds(t.placement),B=!L,j=Nf(D),re=f_(j),Z=t.modifiersData.popperOffsets,oe=t.rects.reference,he=t.rects.popper,Re=typeof Q=="function"?Q(Object.assign({},t.rects,{placement:t.placement})):Q,Ee=typeof Re=="number"?{mainAxis:Re,altAxis:Re}:Object.assign({mainAxis:0,altAxis:0},Re),Ye=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,tt={x:0,y:0};if(Z){if(h){var xe,Xe=j==="y"?Rr:qr,je=j==="y"?xn:on,Qe=j==="y"?"height":"width",ot=Z[j],It=ot+ne[Xe],At=ot-ne[je],cn=z?-he[Qe]/2:0,fn=L===Sl?oe[Qe]:he[Qe],gr=L===Sl?-he[Qe]:-oe[Qe],Wt=t.elements.arrow,vr=z&&Wt?kf(Wt):{width:0,height:0},yr=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:qm(),Gt=yr[Xe],Ft=yr[je],se=Af(0,oe[Qe],vr[Qe]),Ue=B?oe[Qe]/2-cn-se-Gt-Ee.mainAxis:fn-se-Gt-Ee.mainAxis,Kr=B?-oe[Qe]/2+cn+se+Ft+Ee.mainAxis:gr+se+Ft+Ee.mainAxis,Zt=t.elements.arrow&&Ws(t.elements.arrow),st=Zt?j==="y"?Zt.clientTop||0:Zt.clientLeft||0:0,Fe=(xe=Ye?.[j])!=null?xe:0,Fn=ot+Ue-Fe-st,En=ot+Kr-Fe,no=Af(z?Tf(It,Fn):It,ot,z?Us(At,En):At);Z[j]=no,tt[j]=no-ot}if(v){var Ho,lt=j==="x"?Rr:qr,wr=j==="x"?xn:on,fr=Z[re],pt=re==="y"?"height":"width",io=fr+ne[lt],Bn=fr-ne[wr],Mi=[Rr,qr].indexOf(D)!==-1,Gr=(Ho=Ye?.[re])!=null?Ho:0,Yr=Mi?io:fr-oe[pt]-he[pt]-Gr+Ee.altAxis,oo=Mi?fr+oe[pt]+he[pt]-Gr-Ee.altAxis:Bn,hi=z&&Mi?CL(Yr,fr,oo):Af(z?Yr:io,fr,z?oo:Bn);Z[re]=hi,tt[re]=hi-fr}t.modifiersData[s]=tt}}i(Lz,"preventOverflow");var RL={name:"preventOverflow",enabled:!0,phase:"main",fn:Lz,requiresIfExists:["offset"]};function d_(e){return{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}}i(d_,"getHTMLElementScroll");function p_(e){return e===mr(e)||!Cn(e)?Pf(e):d_(e)}i(p_,"getNodeScroll");function Mz(e){var t=e.getBoundingClientRect(),n=xl(t.width)/e.offsetWidth||1,s=xl(t.height)/e.offsetHeight||1;return n!==1||s!==1}i(Mz,"isElementScaled");function h_(e,t,n){n===void 0&&(n=!1);var s=Cn(t),l=Cn(t)&&Mz(t),h=Xn(t),d=fs(e,l,n),v={scrollLeft:0,scrollTop:0},S={x:0,y:0};return(s||!s&&!n)&&((Rn(t)!=="body"||Mf(h))&&(v=p_(t)),Cn(t)?(S=fs(t,!0),S.x+=t.clientLeft,S.y+=t.clientTop):h&&(S.x=Lf(h))),{x:d.left+v.scrollLeft-S.x,y:d.top+v.scrollTop-S.y,width:d.width,height:d.height}}i(h_,"getCompositeRect");function Oz(e){var t=new Map,n=new Set,s=[];e.forEach(function(h){t.set(h.name,h)});function l(h){n.add(h.name);var d=[].concat(h.requires||[],h.requiresIfExists||[]);d.forEach(function(v){if(!n.has(v)){var S=t.get(v);S&&l(S)}}),s.push(h)}return i(l,"sort"),e.forEach(function(h){n.has(h.name)||l(h)}),s}i(Oz,"order");function m_(e){var t=Oz(e);return wL.reduce(function(n,s){return n.concat(t.filter(function(l){return l.phase===s}))},[])}i(m_,"orderModifiers");function g_(e){var t;return function(){return t||(t=new Promise(function(n){Promise.resolve().then(function(){t=void 0,n(e())})})),t}}i(g_,"debounce");function v_(e){var t=e.reduce(function(n,s){var l=n[s.name];return n[s.name]=l?Object.assign({},l,s,{options:Object.assign({},l.options,s.options),data:Object.assign({},l.data,s.data)}):s,n},{});return Object.keys(t).map(function(n){return t[n]})}i(v_,"mergeByName");var DL={placement:"bottom",modifiers:[],strategy:"absolute"};function IL(){for(var e=arguments.length,t=new Array(e),n=0;nNi.default.createElement("li",{role:"separator",className:"divider"}),"Divider");function li({onClick:e,children:t,...n}){return Ni.default.createElement("li",null,Ni.default.createElement("a",{href:"#",onClick:i(l=>{l.preventDefault(),e()},"click"),...n},t))}i(li,"MenuItem");var Yu=Ni.default.memo(i(function({text:t,children:n,options:s,className:l,onOpen:h,...d}){let[v,S]=(0,Ni.useState)(null),[b,k]=(0,Ni.useState)(!1),[R,I]=(0,Ni.useState)(null),{styles:z,attributes:q}=w_(v,R,{...s}),Q=i(D=>{k(D),h&&h(D)},"setOpen");(0,Ni.useEffect)(()=>{R&&document.addEventListener("click",D=>{R.contains(D.target)?document.addEventListener("click",()=>Q(!1),{once:!0}):(D.preventDefault(),D.stopPropagation(),Q(!1))},{once:!0,capture:!0})},[R]);let ne;return b?ne=Ni.default.createElement("ul",{className:"dropdown-menu show",ref:I,style:z.popper,...q.popper},n):ne=null,Ni.default.createElement(Ni.default.Fragment,null,Ni.default.createElement("a",{href:"#",ref:S,className:(0,WL.default)(l,{open:b}),onClick:D=>{D.preventDefault(),Q(!0)},...d},t),ne)},"Dropdown"));function Ym({value:e,onChange:t}){let n=me(l=>l.backendState.contentViews||[]),s=Of.default.createElement("span",null,Of.default.createElement("i",{className:"fa fa-fw fa-files-o"}),"\xA0",Of.default.createElement("b",null,"View:")," ",e.toLowerCase()," ",Of.default.createElement("span",{className:"caret"}));return Of.default.createElement(Yu,{text:s,className:"btn btn-default btn-xs",options:{placement:"top-end"}},n.map(l=>Of.default.createElement(li,{key:l,onClick:()=>t(l)},l.toLowerCase().replace("_"," "))))}i(Ym,"ViewSelector");function x_({flow:e,message:t}){let n=Be(),s=e.request===t?"request":"response",l=me(q=>q.ui.flow.contentViewFor[e.id+s]||"Auto"),h=(0,nr.useRef)(null),[d,v]=(0,nr.useState)(me(q=>q.options.content_view_lines_cutoff)),S=(0,nr.useCallback)(()=>v(Math.max(1024,d*2)),[d]),[b,k]=(0,nr.useState)(!1),R;b?R=On.getContentURL(e,t):R=On.getContentURL(e,t,l,d+1);let I=_0(R,t.contentHash),z=(0,nr.useMemo)(()=>{if(I&&!b)try{return JSON.parse(I)}catch{return{description:"Network Error",lines:[[["error",`${I}`]]]}}else return},[I]);if(b)return nr.default.createElement("div",{className:"contentview",key:"edit"},nr.default.createElement("div",{className:"controls"},nr.default.createElement("h5",null,"[Editing]"),nr.default.createElement(Or,{onClick:i(async()=>{let Q=h.current?.getContent();await n(si(e,{[s]:{content:Q}})),k(!1)},"save"),icon:"fa-check text-success",className:"btn-xs"},"Done"),"\xA0",nr.default.createElement(Or,{onClick:()=>k(!1),icon:"fa-times text-danger",className:"btn-xs"},"Cancel")),nr.default.createElement(Wm,{ref:h,initialContent:I||""}));{let q=z?z.description:"Loading...";return nr.default.createElement("div",{className:"contentview",key:"view"},nr.default.createElement("div",{className:"controls"},nr.default.createElement("h5",null,q),nr.default.createElement(Or,{onClick:()=>k(!0),icon:"fa-edit",className:"btn-xs"},"Edit"),"\xA0",nr.default.createElement(E0,{icon:"fa-upload",text:"Replace",title:"Upload a file to replace the content.",onOpenFile:Q=>n(WA(e,Q,s)),className:"btn btn-default btn-xs"}),"\xA0",nr.default.createElement(Ym,{value:l,onChange:Q=>n(Dy(e.id+s,Q))})),S_.matches(t)&&nr.default.createElement(S_,{flow:e,message:t}),nr.default.createElement(b0,{lines:z?.lines||[],maxLines:d,showMore:S}))}}i(x_,"HttpMessage");var zz=/^image\/(png|jpe?g|gif|webp|vnc.microsoft.icon|x-icon|svg\+xml)$/i;S_.matches=e=>zz.test(On.getContentType(e)||"");function S_({flow:e,message:t}){return nr.default.createElement("div",{className:"flowview-image"},nr.default.createElement("img",{src:On.getContentURL(e,t),alt:"preview",className:"img-thumbnail"}))}i(S_,"ViewImage");function Uz({flow:e}){let t=Be();return qt.createElement("div",{className:"first-line request-line"},qt.createElement("div",null,qt.createElement(wf,{content:e.request.method,onEditDone:n=>t(si(e,{request:{method:n}})),isValid:n=>n.length>0}),"\xA0",qt.createElement(wf,{content:Bs.pretty_url(e.request),onEditDone:n=>t(si(e,{request:{path:"",...Bx(n)}})),isValid:n=>!!Bx(n)?.host}),"\xA0",qt.createElement(wf,{content:e.request.http_version,onEditDone:n=>t(si(e,{request:{http_version:n}})),isValid:Hx})))}i(Uz,"RequestLine");function Wz({flow:e}){let t=Be();return qt.createElement("div",{className:"first-line response-line"},qt.createElement(wf,{content:e.response.http_version,onEditDone:n=>t(si(e,{response:{http_version:n}})),isValid:Hx}),"\xA0",qt.createElement(wf,{content:e.response.status_code+"",onEditDone:n=>t(si(e,{response:{code:parseInt(n)}})),isValid:n=>/^\d+$/.test(n)}),e.response.http_version!=="HTTP/2.0"&&qt.createElement(qt.Fragment,null,"\xA0",qt.createElement(gt,{content:e.response.reason,onEditDone:n=>t(si(e,{response:{msg:n}}))})))}i(Wz,"ResponseLine");function $z({flow:e,message:t}){let n=Be(),s=e.request===t?"request":"response";return qt.createElement(wp,{className:"headers",data:t.headers,onChange:l=>n(si(e,{[s]:{headers:l}}))})}i($z,"Headers");function Vz({flow:e,message:t}){let n=Be(),s=e.request===t?"request":"response";return!On.get_first_header(t,/^trailer$/i)?null:qt.createElement(qt.Fragment,null,qt.createElement("hr",null),qt.createElement("h5",null,"HTTP Trailers"),qt.createElement(wp,{className:"trailers",data:t.trailers,onChange:h=>n(si(e,{[s]:{trailers:h}}))}))}i(Vz,"Trailers");var VL=qt.memo(i(function({flow:t,message:n}){let s=t.request===n?"request":"response",l=t.request===n?Uz:Wz;return qt.createElement("section",{className:s},qt.createElement(l,{flow:t}),qt.createElement($z,{flow:t,message:n}),qt.createElement("hr",null),qt.createElement(x_,{key:t.id+s,flow:t,message:n}),qt.createElement(Vz,{flow:t,message:n}))},"Message"));function C_(){let e=me(t=>t.flows.byId[t.flows.selected[0]]);return qt.createElement(VL,{flow:e,message:e.request})}i(C_,"Request");C_.displayName="Request";function __(){let e=me(t=>t.flows.byId[t.flows.selected[0]]);return qt.createElement(VL,{flow:e,message:e.response})}i(__,"Response");__.displayName="Response";var et=pe(Te());var qz=i(({message:e})=>et.createElement("div",null,e.query?e.op_code:e.response_code,"\xA0",e.truncation?"(Truncated)":""),"Summary"),jz=i(({message:e})=>et.createElement(et.Fragment,null,et.createElement("h5",null,e.recursion_desired?"Recursive ":"","Question"),et.createElement("table",null,et.createElement("thead",null,et.createElement("tr",null,et.createElement("th",null,"Name"),et.createElement("th",null,"Type"),et.createElement("th",null,"Class"))),et.createElement("tbody",null,e.questions.map((t,n)=>et.createElement("tr",{key:n},et.createElement("td",null,t.name),et.createElement("td",null,t.type),et.createElement("td",null,t.class)))))),"Questions"),E_=i(({name:e,values:t})=>et.createElement(et.Fragment,null,et.createElement("h5",null,e),t.length>0?et.createElement("table",null,et.createElement("thead",null,et.createElement("tr",null,et.createElement("th",null,"Name"),et.createElement("th",null,"Type"),et.createElement("th",null,"Class"),et.createElement("th",null,"TTL"),et.createElement("th",null,"Data"))),et.createElement("tbody",null,t.map((n,s)=>et.createElement("tr",{key:s},et.createElement("td",null,n.name),et.createElement("td",null,n.type),et.createElement("td",null,n.class),et.createElement("td",null,n.ttl),et.createElement("td",null,n.data))))):"\u2014"),"ResourceRecords"),qL=i(({type:e,message:t})=>et.createElement("section",{className:"dns-"+e},et.createElement("div",{className:`first-line ${e}-line`},et.createElement(qz,{message:t})),et.createElement(jz,{message:t}),et.createElement("hr",null),et.createElement(E_,{name:`${t.authoritative_answer?"Authoritative ":""}${t.recursion_available?"Recursive ":""}Answer`,values:t.answers}),et.createElement("hr",null),et.createElement(E_,{name:"Authority",values:t.authorities}),et.createElement("hr",null),et.createElement(E_,{name:"Additional",values:t.additionals})),"Message");function b_(){let e=me(t=>t.flows.byId[t.flows.selected[0]]);return et.createElement(qL,{type:"request",message:e.request})}i(b_,"Request");b_.displayName="Request";function T_(){let e=me(t=>t.flows.byId[t.flows.selected[0]]);return et.createElement(qL,{type:"response",message:e.response})}i(T_,"Response");T_.displayName="Response";var be=pe(Te());function jL({conn:e}){let t=null;return"address"in e?t=be.createElement(be.Fragment,null,be.createElement("tr",null,be.createElement("td",null,"Address:"),be.createElement("td",null,e.address?.join(":"))),e.peername&&be.createElement("tr",null,be.createElement("td",null,"Resolved address:"),be.createElement("td",null,e.peername.join(":"))),e.sockname&&be.createElement("tr",null,be.createElement("td",null,"Source address:"),be.createElement("td",null,e.sockname.join(":")))):e.peername?.[0]&&(t=be.createElement(be.Fragment,null,be.createElement("tr",null,be.createElement("td",null,"Address:"),be.createElement("td",null,e.peername?.join(":"))))),be.createElement("table",{className:"connection-table"},be.createElement("tbody",null,t,e.sni?be.createElement("tr",null,be.createElement("td",null,be.createElement("abbr",{title:"TLS Server Name Indication"},"SNI"),":"),be.createElement("td",null,e.sni)):null,e.alpn?be.createElement("tr",null,be.createElement("td",null,be.createElement("abbr",{title:"ALPN protocol negotiated"},"ALPN"),":"),be.createElement("td",null,e.alpn)):null,e.tls_version?be.createElement("tr",null,be.createElement("td",null,"TLS Version:"),be.createElement("td",null,e.tls_version)):null,e.cipher?be.createElement("tr",null,be.createElement("td",null,"TLS Cipher:"),be.createElement("td",null,e.cipher)):null))}i(jL,"ConnectionInfo");function KL(e){return be.createElement("dl",{className:"cert-attributes"},e.map(([t,n])=>be.createElement(be.Fragment,{key:t},be.createElement("dt",null,t),be.createElement("dd",null,n))))}i(KL,"attrList");function Kz({flow:e}){let t=e.server_conn?.cert;return t?be.createElement(be.Fragment,null,be.createElement("h4",{key:"name"},"Server Certificate"),be.createElement("table",{className:"certificate-table"},be.createElement("tbody",null,be.createElement("tr",null,be.createElement("td",null,"Type"),be.createElement("td",null,t.keyinfo[0],", ",t.keyinfo[1]," bits")),be.createElement("tr",null,be.createElement("td",null,"SHA256 digest"),be.createElement("td",null,t.sha256)),be.createElement("tr",null,be.createElement("td",null,"Valid from"),be.createElement("td",null,Oo(t.notbefore,{milliseconds:!1}))),be.createElement("tr",null,be.createElement("td",null,"Valid to"),be.createElement("td",null,Oo(t.notafter,{milliseconds:!1}))),be.createElement("tr",null,be.createElement("td",null,"Subject Alternative Names"),be.createElement("td",null,t.altnames.join(", "))),be.createElement("tr",null,be.createElement("td",null,"Subject"),be.createElement("td",null,KL(t.subject))),be.createElement("tr",null,be.createElement("td",null,"Issuer"),be.createElement("td",null,KL(t.issuer))),be.createElement("tr",null,be.createElement("td",null,"Serial"),be.createElement("td",null,t.serial))))):be.createElement(be.Fragment,null)}i(Kz,"CertificateInfo");function R0({flow:e}){return be.createElement("section",{className:"detail"},be.createElement("h4",null,"Client Connection"),be.createElement(jL,{conn:e.client_conn}),e.server_conn?.address&&be.createElement(be.Fragment,null,be.createElement("h4",null,"Server Connection"),be.createElement(jL,{conn:e.server_conn})),be.createElement(Kz,{flow:e}))}i(R0,"Connection");R0.displayName="Connection";var Xm=pe(Te());function D0({flow:e}){return Xm.createElement("section",{className:"error"},Xm.createElement("div",{className:"alert alert-warning"},e.error.msg,Xm.createElement("div",null,Xm.createElement("small",null,Oo(e.error.timestamp)))))}i(D0,"Error");D0.displayName="Error";var Vs=pe(Te());function Gz({t:e,deltaTo:t,title:n}){return e?Vs.createElement("tr",null,Vs.createElement("td",null,n,":"),Vs.createElement("td",null,Oo(e),t&&Vs.createElement("span",{className:"text-muted"},"(",Fy(1e3*(e-t)),")"))):Vs.createElement("tr",null)}i(Gz,"TimeStamp");function I0({flow:e}){let t;e.type==="http"?t=e.request.timestamp_start:t=e.client_conn.timestamp_start;let n=[{title:"Server conn. initiated",t:e.server_conn?.timestamp_start,deltaTo:t},{title:"Server conn. TCP handshake",t:e.server_conn?.timestamp_tcp_setup,deltaTo:t},{title:"Server conn. TLS handshake",t:e.server_conn?.timestamp_tls_setup,deltaTo:t},{title:"Server conn. closed",t:e.server_conn?.timestamp_end,deltaTo:t},{title:"Client conn. established",t:e.client_conn.timestamp_start,deltaTo:e.type==="http"?t:void 0},{title:"Client conn. TLS handshake",t:e.client_conn.timestamp_tls_setup,deltaTo:t},{title:"Client conn. closed",t:e.client_conn.timestamp_end,deltaTo:t}];return e.type==="http"&&n.push({title:"First request byte",t:e.request.timestamp_start},{title:"Request complete",t:e.request.timestamp_end,deltaTo:t},{title:"First response byte",t:e.response?.timestamp_start,deltaTo:t},{title:"Response complete",t:e.response?.timestamp_end,deltaTo:t}),Vs.createElement("section",{className:"timing"},Vs.createElement("h4",null,"Timing"),Vs.createElement("table",{className:"timing-table"},Vs.createElement("tbody",null,n.filter(s=>!!s.t).sort((s,l)=>s.t-l.t).map(({title:s,t:l,deltaTo:h})=>Vs.createElement(Gz,{key:s,title:s,t:l,deltaTo:h})))))}i(I0,"Timing");I0.displayName="Timing";var Xu=pe(Te());var Ea=pe(Te()),Tp=pe(Te());function Rf({flow:e,messages_meta:t}){let n=Be(),s=me(k=>k.ui.flow.contentViewFor[e.id+"messages"]||"Auto"),[l,h]=(0,Tp.useState)(me(k=>k.options.content_view_lines_cutoff)),d=(0,Tp.useCallback)(()=>h(Math.max(1024,l*2)),[l]),v=_0(On.getContentURL(e,"messages",s,l+1),e.id+t.count),S=(0,Tp.useMemo)(()=>{if(v)try{return JSON.parse(v)}catch{return[{description:"Network Error",lines:[[["error",`${v}`]]]}]}},[v])||[],b=l;return Ea.createElement("div",{className:"contentview"},Ea.createElement("div",{className:"controls"},Ea.createElement("h5",null,t.count," Messages"),Ea.createElement(Ym,{value:s,onChange:k=>n(Dy(e.id+"messages",k))})),S.map((k,R)=>{let I=`fa fa-fw fa-arrow-${k.from_client?"right text-primary":"left text-danger"}`,z=Ea.createElement("div",{key:R},Ea.createElement("small",null,Ea.createElement("i",{className:I}),Ea.createElement("span",{className:"pull-right"},k.timestamp&&Oo(k.timestamp))),Ea.createElement(b0,{lines:k.lines,maxLines:b,showMore:d}));return b-=k.lines.length,z}))}i(Rf,"Messages");function F0({flow:e}){return Xu.createElement("section",{className:"websocket"},Xu.createElement("h4",null,"WebSocket"),Xu.createElement(Rf,{flow:e,messages_meta:e.websocket.messages_meta}),Xu.createElement(Yz,{websocket:e.websocket}))}i(F0,"WebSocket");F0.displayName="WebSocket";function Yz({websocket:e}){if(!e.timestamp_end)return null;let t=e.close_reason?`(${e.close_reason})`:"";return Xu.createElement("div",null,Xu.createElement("i",{className:"fa fa-fw fa-window-close text-muted"}),"\xA0 Closed by ",e.closed_by_client?"client":"server"," ","with code ",e.close_code," ",t,".",Xu.createElement("small",{className:"pull-right"},Oo(e.timestamp_end)))}i(Yz,"CloseSummary");var B0=pe(Te());function H0({flow:e}){let t=Be();return B0.createElement("section",{className:"timing"},B0.createElement("h4",null,"Comment"),B0.createElement(gt,{className:"kv-value",content:e.comment,onEditDone:n=>{t(si(e,{comment:n}))},placeholder:"empty"}))}i(H0,"Comment");H0.displayName="Comment";var YL=pe(ai());var k_=pe(Te());function z0({flow:e}){return k_.createElement("section",{className:"tcp"},k_.createElement(Rf,{flow:e,messages_meta:e.messages_meta}))}i(z0,"TcpMessages");z0.displayName="Stream Data";var N_=pe(Te());function U0({flow:e}){return N_.createElement("section",{className:"udp"},N_.createElement(Rf,{flow:e,messages_meta:e.messages_meta}))}i(U0,"UdpMessages");U0.displayName="Datagrams";var GL={request:C_,response:__,error:D0,connection:R0,timing:I0,websocket:F0,tcpmessages:z0,udpmessages:U0,dnsrequest:b_,dnsresponse:T_,comment:H0};function W0(e){let t;switch(e.type){case"http":t=["request","response","websocket"].filter(n=>e[n]);break;case"tcp":t=["tcpmessages"];break;case"udp":t=["udpmessages"];break;case"dns":t=["request","response"].filter(n=>e[n]).map(n=>"dns"+n);break}return e.error&&t.push("error"),t.push("connection"),t.push("timing"),t.push("comment"),t}i(W0,"tabsForFlow");function A_(){let e=Be(),t=me(h=>h.flows.byId[h.flows.selected[0]]),n=me(h=>h.ui.flow.tab);if(t==null)return ba.createElement(ba.Fragment,null);let s=W0(t);s.indexOf(n)<0&&(n==="response"&&t.error?n="error":n==="error"&&"response"in t?n="response":n=s[0]);let l=GL[n];return ba.createElement("div",{className:"flow-detail"},ba.createElement("nav",{className:"nav-tabs nav-tabs-sm"},ba.createElement("button",{"data-testid":"close-button-id",className:"close-button",onClick:()=>e(yl(void 0))},ba.createElement("i",{className:"fa fa-times-circle"})),s.map(h=>ba.createElement("a",{key:h,href:"#",className:(0,YL.default)({active:n===h}),onClick:d=>{d.preventDefault(),e(mf(h))}},GL[h].displayName))),ba.createElement(l,{flow:t}))}i(A_,"FlowView");function XL(e){if(e.ctrlKey||e.metaKey)return()=>{};let t=e.key;return e.preventDefault(),(n,s)=>{let l=s().flows,h=l.byId[s().flows.selected[0]];switch(t){case"k":case"ArrowUp":n(yf(l,-1));break;case"j":case"ArrowDown":n(yf(l,1));break;case" ":case"PageDown":n(yf(l,10));break;case"PageUp":n(yf(l,-10));break;case"End":n(yf(l,1e10));break;case"Home":n(yf(l,-1e10));break;case"Escape":s().ui.modal.activeModal?n(Xy()):n(yl(void 0));break;case"ArrowLeft":{if(!h)break;let d=W0(h),v=s().ui.flow.tab,S=d[(Math.max(0,d.indexOf(v))-1+d.length)%d.length];n(mf(S));break}case"Tab":case"ArrowRight":{if(!h)break;let d=W0(h),v=s().ui.flow.tab,S=d[(Math.max(0,d.indexOf(v))+1)%d.length];n(mf(S));break}case"Delete":case"d":{if(!h)return;n(qy(h));break}case"n":{gf("view.flows.create","get","https://example.com/");break}case"D":{if(!h)return;n(jy(h));break}case"a":{h&&h.intercepted&&n(lp(h));break}case"A":{n($y());break}case"r":{h&&n(up(h));break}case"v":{h&&h.modified&&n(Ky(h));break}case"x":{h&&h.intercepted&&n(Vy(h));break}case"X":{n(UA());break}case"z":{n(Gy());break}default:return}}}i(XL,"onKeyDown");var Ta=pe(Te());var kp=pe(Te()),QL=pe(ai());var Qm=class extends kp.Component{constructor(n,s){super(n,s);this.node=kp.default.createRef();this.state={applied:!1,startPos:0,dragPointer:.1},this.onLostPointerCapture=this.onLostPointerCapture.bind(this),this.onPointerDown=this.onPointerDown.bind(this),this.onPointerMove=this.onPointerMove.bind(this)}static{i(this,"Splitter")}static{this.defaultProps={axis:"x"}}onPointerDown(n){this.state.dragPointer===.1&&(n.target.setPointerCapture(n.pointerId),this.setState({startPos:this.props.axis==="x"?n.pageX:n.pageY,dragPointer:n.pointerId}))}onLostPointerCapture(n){if(this.state.dragPointer!==n.pointerId)return;let s=this.node.current,l=s.previousElementSibling,h=s.nextElementSibling;s.style.transform="",l.style.flex=`0 0 ${Math.max(0,(this.props.axis==="x"?l.offsetWidth+n.pageX:l.offsetHeight+n.pageY)-this.state.startPos)}px`,h.style.flex="1 1 auto",this.setState({applied:!0,dragPointer:.1}),this.onResize()}onPointerMove(n){this.state.dragPointer===n.pointerId&&(this.node.current.style.transform=this.props.axis==="x"?`translateX(${n.pageX-this.state.startPos}px)`:`translateY(${n.pageY-this.state.startPos}px)`)}onResize(){window.setTimeout(()=>window.dispatchEvent(new CustomEvent("resize")),1)}reset(n){this.state.applied&&(this.node.current?.previousElementSibling instanceof HTMLElement&&(this.node.current.previousElementSibling.style.flex=""),this.node.current?.nextElementSibling instanceof HTMLElement&&(this.node.current.nextElementSibling.style.flex=""),n||this.setState({applied:!1}),this.onResize())}componentWillUnmount(){this.reset(!0)}render(){return kp.default.createElement("div",{ref:this.node,className:(0,QL.default)("splitter",this.props.axis==="x"?"splitter-x":"splitter-y")},kp.default.createElement("div",{onLostPointerCapture:this.onLostPointerCapture,onPointerDown:this.onPointerDown,onPointerMove:this.onPointerMove}))}};var Qi=pe(Te());var Jm=i(e=>{let t=e.current;return t===null||t.scrollTop===0?!1:Math.ceil(t.scrollTop)+t.clientHeight>=t.scrollHeight},"isAtBottom"),$0=i(e=>{e.current&&!Jm(e)&&(e.current.scrollTop=e.current.scrollHeight)},"adjustScrollTop");function Df(e=void 0){if(!e)return{start:0,end:0,paddingTop:0,paddingBottom:0};let{itemCount:t,rowHeight:n,viewportTop:s,viewportHeight:l,itemHeights:h}=e,d=s+l,v=0,S=0,b=0,k=0;if(h){let R=0;for(let I=0;I0&&RU_,default:()=>Qz,icon:()=>O_,index:()=>M_,method:()=>D_,path:()=>R_,quickactions:()=>If,size:()=>B_,status:()=>F_,time:()=>H_,timestamp:()=>z_,tls:()=>L_,version:()=>I_});var Jt=pe(Te());var P_=pe(ai());var L_=i(({flow:e})=>Jt.default.createElement("td",{className:(0,P_.default)("col-tls",e.client_conn.tls_established?"col-tls-https":"col-tls-http")}),"tls");L_.headerName="";var M_=i(({flow:e})=>{let t=me(n=>n.flows.listIndex[e.id]);return Jt.default.createElement("td",{className:"col-index"},t+1)},"index");M_.headerName="#";var O_=i(({flow:e})=>Jt.default.createElement("td",{className:"col-icon"},Jt.default.createElement("div",{className:(0,P_.default)("resource-icon",Wx(e))})),"icon");O_.headerName="";var R_=i(({flow:e})=>{let t;return e.error&&(e.error.msg==="Connection killed."?t=Jt.default.createElement("i",{className:"fa fa-fw fa-times pull-right"}):t=Jt.default.createElement("i",{className:"fa fa-fw fa-exclamation pull-right"})),Jt.default.createElement("td",{className:"col-path"},e.is_replay==="request"&&Jt.default.createElement("i",{className:"fa fa-fw fa-repeat pull-right"}),e.intercepted&&Jt.default.createElement("i",{className:"fa fa-fw fa-pause pull-right"}),t,Jt.default.createElement("span",{className:"marker pull-right"},e.marked),$x(e))},"path");R_.headerName="Path";var D_=i(({flow:e})=>Jt.default.createElement("td",{className:"col-method"},qx(e)),"method");D_.headerName="Method";var I_=i(({flow:e})=>Jt.default.createElement("td",{className:"col-http-version"},jx(e)),"version");I_.headerName="Version";var F_=i(({flow:e})=>{let t="darkred";return e.type!=="http"&&e.type!="dns"||!e.response?Jt.default.createElement("td",{className:"col-status"}):(100<=e.response.status_code&&e.response.status_code<200?t="green":200<=e.response.status_code&&e.response.status_code<300?t="darkgreen":300<=e.response.status_code&&e.response.status_code<400?t="lightblue":(400<=e.response.status_code&&e.response.status_code<500||500<=e.response.status_code&&e.response.status_code<600)&&(t="red"),Jt.default.createElement("td",{className:"col-status",style:{color:t}},Vx(e)))},"status");F_.headerName="Status";var B_=i(({flow:e})=>Jt.default.createElement("td",{className:"col-size"},Iy(Ux(e))),"size");B_.headerName="Size";var H_=i(({flow:e})=>{let t=Pm(e),n=zx(e);return Jt.default.createElement("td",{className:"col-time"},t&&n?Fy(1e3*(n-t)):"...")},"time");H_.headerName="Time";var z_=i(({flow:e})=>{let t=Pm(e);return Jt.default.createElement("td",{className:"col-timestamp"},t?Oo(t):"...")},"timestamp");z_.headerName="Start time";var If=i(({flow:e})=>{let t=Be(),n=null;return e.intercepted?n=Jt.default.createElement("a",{href:"#",className:"quickaction",onClick:()=>t(lp(e))},Jt.default.createElement("i",{className:"fa fa-fw fa-play text-success"})):zy(e)&&(n=Jt.default.createElement("a",{href:"#",className:"quickaction",onClick:()=>t(up(e))},Jt.default.createElement("i",{className:"fa fa-fw fa-repeat text-primary"}))),Jt.default.createElement("td",{className:"col-quickactions"},n?Jt.default.createElement("div",null,n):Jt.default.createElement(Jt.default.Fragment,null))},"quickactions");If.headerName="";var U_=i(({flow:e})=>{let t=e.comment;return Jt.default.createElement("td",{className:"col-comment"},t)},"comment");U_.headerName="Comment";var Xz={icon:O_,index:M_,method:D_,version:I_,path:R_,quickactions:If,size:B_,status:F_,time:H_,timestamp:z_,tls:L_,comment:U_},Qz=Xz;var eM=eg.memo(i(function(){let t=Be(),n=me(v=>v.flows.sort.desc),s=me(v=>v.flows.sort.column),l=me(v=>v.options.web_columns),h=n?"sort-desc":"sort-asc",d=l.map(v=>Zm[v]).filter(v=>v).concat(If);return eg.createElement("tr",null,d.map(v=>eg.createElement("th",{className:(0,ZL.default)(`col-${v.name}`,s===v.name&&h),key:v.name,onClick:()=>t(zA(v.name===s&&n?void 0:v.name,v.name!==s?!1:!n))},v.headerName)))},"FlowTableHead"));var Np=pe(Te()),tM=pe(ai());var rM=Np.default.memo(i(function({flow:t,selected:n,highlighted:s}){let l=Be(),h=me(b=>b.options.web_columns),d=(0,tM.default)({selected:n,highlighted:s,intercepted:t.intercepted,"has-request":t.type==="http"&&t.request,"has-response":t.type==="http"&&t.response}),v=(0,Np.useCallback)(b=>{let k=b.target;for(;k.parentNode;){if(k.classList.contains("col-quickactions"))return;k=k.parentNode}l(yl(t.id))},[t]),S=h.map(b=>Zm[b]).filter(b=>b).concat(If);return Np.default.createElement("tr",{className:d,onClick:v},S.map(b=>Np.default.createElement(b,{key:b.name,flow:t})))},"FlowRow"));var W_=class extends Qi.Component{constructor(n,s){super(n,s);this.viewport=Qi.createRef();this.head=Qi.createRef();this.state={vScroll:Df(),viewportTop:0},this.onViewportUpdate=this.onViewportUpdate.bind(this)}static{i(this,"PureFlowTable")}static{this.defaultProps={rowHeight:32}}componentDidMount(){window.addEventListener("resize",this.onViewportUpdate),this.onViewportUpdate()}componentWillUnmount(){window.removeEventListener("resize",this.onViewportUpdate)}getSnapshotBeforeUpdate(){return Jm(this.viewport)}componentDidUpdate(n,s,l){if(l&&$0(this.viewport),this.onViewportUpdate(),this.props.selected&&this.props.selected!==n.selected){let{rowHeight:d,flows:v,selected:S}=this.props,b=this.viewport.current,k=this.head.current,R=k?k.offsetHeight:0,I=v.indexOf(S)*d+R,z=I+d,q=b.scrollTop,Q=b.offsetHeight;I-Rq+Q&&(b.scrollTop=z-Q),this.onViewportUpdate()}}onViewportUpdate(){let n=this.viewport.current,s=n.scrollTop||0,l=Df({viewportTop:s,viewportHeight:n.offsetHeight||0,itemCount:this.props.flows.length,rowHeight:this.props.rowHeight});if(this.state.viewportTop!==s||!Mo(this.state.vScroll,l)){let h=Math.min(s,l.end*this.props.rowHeight);this.setState({vScroll:l,viewportTop:h})}}render(){let{vScroll:n,viewportTop:s}=this.state,{flows:l,selected:h,highlight:d}=this.props,v=d?vf.parse(d):()=>!1;return Qi.createElement("div",{className:"flow-table",onScroll:this.onViewportUpdate,ref:this.viewport},Qi.createElement("table",null,Qi.createElement("thead",{ref:this.head,style:{transform:`translateY(${s}px)`}},Qi.createElement(eM,null)),Qi.createElement("tbody",null,Qi.createElement("tr",{style:{height:n.paddingTop}}),l.slice(n.start,n.end).map(S=>Qi.createElement(rM,{key:S.id,flow:S,selected:S===h,highlighted:v(S)})),Qi.createElement("tr",{style:{height:n.paddingBottom}}))))}},nM=Wu(e=>({flows:e.flows.view,highlight:e.flows.highlight,selected:e.flows.byId[e.flows.selected[0]]}))(W_);var an=pe(Te()),tw=pe(Te());var sO=pe(oO());function dE(){return an.createElement("div",{style:{padding:"1em 2em"}},an.createElement("h3",null,"mitmproxy is running."),an.createElement("p",null,"No flows have been recorded yet.",an.createElement("br",null),"To start capturing traffic, please configure your settings in the Capture tab."))}i(dE,"CaptureSetup");function jU({description:e,listen_addrs:t,is_running:n,wireguard_conf:s,type:l}){let h=(0,tw.useRef)(null);(0,tw.useEffect)(()=>{s&&h.current&&sO.default.toCanvas(h.current,s,{margin:0,scale:3})},[s]);let d,v=t.length===1||t.length===2&&t[0][1]===t[1][1],S=t.every(k=>["::","0.0.0.0"].includes(k[0]));v&&S?d=Tx(["*",t[0][1]]):d=t.map(Tx).join(" and "),e=e[0].toUpperCase()+e.substr(1);let b;return n?b=an.createElement(an.Fragment,null,l==="local"?an.createElement("div",{className:"text-success"},e," is active."):an.createElement("div",{className:"text-success"},e," listening at ",d,"."),s&&an.createElement("div",{className:"wireguard-config"},an.createElement("pre",null,s),an.createElement("canvas",{ref:h}))):b=an.createElement(an.Fragment,null,an.createElement("div",{className:"text-warning"},e," starting...")),an.createElement("div",null,b)}i(jU,"ServerDescription");function ui({error:e,backendState:t}){return an.createElement("div",{className:"mode-status"},e?an.createElement("div",{className:"text-danger"},e):t&&an.createElement(jU,{...t}))}i(ui,"ServerStatus");var In=pe(Te());var Ai=pe(Te());var Rp=pe(Te());function ci({value:e,onChange:t,children:n,label:s}){let l=Rp.useId();return Rp.createElement("div",{className:"mode-entry"},Rp.createElement("input",{type:"checkbox",name:`mode-checkbox-${l}`,id:`mode-checkbox-${l}`,checked:e,onChange:t}),Rp.createElement("label",{htmlFor:`mode-checkbox-${l}`,style:{marginBottom:0,fontWeight:"normal"}},s),n)}i(ci,"ModeToggle");var ln=pe(Te());var Fo=pe(Te());function fi({children:e,iconClass:t,classname:n,isVisible:s}){let l=Fo.useId(),h="--"+[...l].map(S=>S.charCodeAt(0).toString(16)).join(""),d=Fo.useRef(null),v=Fo.useRef(null);return Fo.useEffect(()=>{d.current.style.anchorName=h,v.current.style.positionAnchor=h},[]),Fo.useEffect(()=>{s===!0&&document.getElementById(l)?.showPopover()},[s]),Fo.createElement("div",{className:n?`mode-popover ${n}`:"mode-popover"},Fo.createElement("button",{popovertarget:l,ref:d},Fo.createElement("i",{className:t,"aria-hidden":"true"})),Fo.createElement("div",{id:l,popover:"auto",ref:v},e))}i(fi,"Popover");function pE({server:e}){let{currentProcesses:t,isLoading:n}=me(D=>D.processes),{selectedProcesses:s}=me(D=>D.modes.local[0]),[l,h]=ln.useState([]),[d,v]=ln.useState(""),S=Be(),{platform:b}=me(D=>D.backendState),k=i(D=>{v(D.target.value)},"handleInputChange"),R=i(D=>{let L=b.startsWith("win32")?"\\":"/";return Tm(D.executable,L)[1]},"extractProcessName"),I=i(D=>{if(z(D)&&s){let B=s.split(", ").filter(j=>j!==R(D)).join(", ");S(yp({server:e,value:B}));return}let L=s?`${s}, ${R(D)}`:R(D);S(yp({server:e,value:L}))},"handleApplicationClick"),z=i(D=>{let L=R(D);return s?.includes(L)},"isSelected");ln.useEffect(()=>{t.length===0&&S(Cf())},[]),ln.useEffect(()=>{if(d){let D=t.filter(L=>R(L).toLowerCase().includes(d.toLowerCase()));h(D)}else l!==t&&h(t)},[d,t]);let q=i(D=>{D.stopPropagation()},"handleInputKeyDown"),[Q,ne]=ln.useState(!1);return ln.createElement("div",{className:"local-dropdown"},ln.createElement("div",{className:"dropdown-header"},ln.createElement("input",{type:"text",className:"autocomplete-input",placeholder:s&&s?.length>0?"Add more":"(all applications)",value:d,onChange:k,onKeyDown:q,onClick:()=>ne(!0),onBlur:()=>ne(!1)}),ln.createElement(fi,{iconClass:"fa fa-chevron-down",classname:"local-popover",isVisible:Q},ln.createElement("h4",null,"Current Applications running on machine"),n?ln.createElement("i",{className:"fa fa-spinner","aria-hidden":"true"}):l.length>0?ln.createElement("ul",{className:"dropdown-list"},l.map((D,L)=>ln.createElement("li",{key:L,className:`dropdown-item ${z(D)?"selected":""}`,onClick:()=>I(D),role:"menuitem"},ln.createElement("div",{className:"process-details"},ln.createElement("img",{className:"process-icon",src:`./executable-icon?path=${D.executable}`,loading:"lazy"}),ln.createElement("span",{className:"process-name"},R(D)))))):ln.createElement("span",null,"No results"))))}i(pE,"LocalDropdown");function hE(){let e=me(s=>s.modes.local),t=me(s=>s.backendState.servers),n=e.map(s=>Ai.createElement(KU,{key:s.ui_id,server:s,backendState:t[h0(s)]}));return Ai.createElement("div",null,Ai.createElement("h4",{className:"mode-title"},"Local Applications"),Ai.createElement("p",{className:"mode-description"},"Transparently Intercept local application(s)."),n)}i(hE,"Local");function KU({server:e,backendState:t}){let n=Be(),s=me(d=>d.processes.error),l=e.error||t?.last_exception||s||void 0,h=i(d=>{let v=e.selectedProcesses?.split(", ").filter(S=>S!==d).join(", ");n(yp({server:e,value:v}))},"handleDeletionProcess");return Ai.createElement("div",{className:"mode-local"},Ai.createElement(ci,{value:e.active,label:"Intercept traffic for",onChange:()=>n(MC({server:e,value:!e.active}))},Ai.createElement("div",{className:"processes-container"},Ai.createElement("div",{className:"selected-processes"},e.selectedProcesses?.split(", ").filter(d=>d.trim()!=="").map(d=>Ai.createElement("div",{key:d,className:"selected-process"},d,Ai.createElement("i",{className:"fa fa-times","aria-hidden":"true",onClick:()=>h(d)})))),Ai.createElement("div",{className:"dropdown-container"},Ai.createElement(pE,{server:e}),Ai.createElement("i",{className:"fa fa-refresh","aria-hidden":"true",onClick:()=>n(Cf())})))),Ai.createElement(ui,{error:l,backendState:t}))}i(KU,"LocalRow");var Ji=pe(Te());function mE(){let e=me(s=>s.modes.regular),t=me(s=>s.backendState.servers),n=e.map(s=>Ji.createElement(GU,{key:s.ui_id,server:s,backendState:t[p0(s)]}));return Ji.createElement("div",null,Ji.createElement("h4",{className:"mode-title"},"Explicit HTTP(S) Proxy"),Ji.createElement("p",{className:"mode-description"},"You manually configure your client application or device to use an HTTP(S) proxy."),n)}i(mE,"Regular");function GU({server:e,backendState:t}){let n=Be(),s=e.error||t?.last_exception||void 0;return Ji.createElement("div",null,Ji.createElement(ci,{value:e.active,label:"Run HTTP/S Proxy",onChange:()=>n(AC({server:e,value:!e.active}))},Ji.createElement(fi,{iconClass:"fa fa-cog"},Ji.createElement("h4",null,"Advanced Configuration"),Ji.createElement("p",null,"Listen Host"),Ji.createElement(gt,{className:"mode-input",content:e.listen_host||"",onEditDone:l=>n(PC({server:e,value:l}))}),Ji.createElement("p",null,"Listen Port"),Ji.createElement(gt,{className:"mode-input",content:e.listen_port?e.listen_port.toString():"",placeholder:"8080",onEditDone:l=>n(LC({server:e,value:parseInt(l)}))}))),Ji.createElement(ui,{error:s,backendState:t}))}i(GU,"RegularRow");var di=pe(Te());function gE(){let e=me(s=>s.modes.wireguard),t=me(s=>s.backendState.servers),n=e.map(s=>di.createElement(YU,{key:s.ui_id,server:s,backendState:t[m0(s)]}));return di.createElement("div",null,di.createElement("h4",{className:"mode-title"},"WireGuard Server"),di.createElement("p",{className:"mode-description"},"Start a WireGuard\u2122 server and connect an external device for transparent proxying."),n)}i(gE,"Wireguard");function YU({server:e,backendState:t}){let n=Be(),s=e.error||t?.last_exception||void 0;return di.createElement("div",null,di.createElement(ci,{value:e.active,label:"Run WireGuard Server",onChange:()=>n(OC({server:e,value:!e.active}))},di.createElement(fi,{iconClass:"fa fa-cog"},di.createElement("h4",null,"Advanced Configuration"),di.createElement("p",null,"Listen Host"),di.createElement(gt,{className:"mode-input",content:e.listen_host||"",placeholder:"(all interfaces)",onEditDone:l=>n(RC({server:e,value:l}))}),di.createElement("p",null,"Listen Port"),di.createElement(gt,{className:"mode-input",content:e.listen_port?e.listen_port.toString():"",placeholder:"51820",onEditDone:l=>n(DC({server:e,value:parseInt(l)}))}),di.createElement("p",null,"Configuration File"),di.createElement(gt,{className:"mode-input",content:e.file_path||"",placeholder:"~/.mitmproxy/wireguard.conf",onEditDone:l=>n(IC({server:e,value:l}))}))),di.createElement(ui,{error:s,backendState:t}))}i(YU,"WireGuardRow");var jr=pe(Te());function vE(){let e=Be(),t=me(s=>s.modes.reverse),n=me(s=>s.backendState.servers);return jr.createElement("div",null,jr.createElement("h4",{className:"mode-title"},"Reverse Proxy"),jr.createElement("p",{className:"mode-description"},"Requests are forwarded to a preconfigured destination."),jr.createElement("div",{className:"mode-reverse-servers"},t.map((s,l)=>jr.createElement(XU,{key:s.ui_id,removable:l>0,server:s,backendState:n[vp(s)]})),jr.createElement("div",{className:"mode-reverse-add-server",onClick:()=>e(ZP())},jr.createElement("i",{className:"fa fa-plus-square-o","aria-hidden":"true"}),"Add additional server")))}i(vE,"Reverse");function XU({removable:e,server:t,backendState:n}){let s=Be(),l=Object.values(g0),h=i(async()=>{t.active&&await s(C0({server:t,value:!1})).unwrap(),await s(eL(t))},"deleteServer"),d=t.error||n?.last_exception||void 0;return jr.createElement("div",null,jr.createElement(ci,{value:t.active,label:"Forward",onChange:()=>{s(C0({server:t,value:!t.active}))}},jr.createElement("select",{name:"protocols",className:"mode-reverse-dropdown",value:t.protocol,onChange:v=>{s(HC({server:t,value:v.target.value}))}},l.map(v=>jr.createElement("option",{key:v,value:v},v))),"traffic to",jr.createElement(gt,{className:"mode-reverse-input",content:t.destination?.toString()||"",onEditDone:v=>s(zC({server:t,value:v})),placeholder:"example.com"}),jr.createElement(fi,{iconClass:"fa fa-cog"},jr.createElement("h4",null,"Advanced Configuration"),jr.createElement("p",null,"Listen Host"),jr.createElement(gt,{className:"mode-reverse-input",content:t.listen_host||"",onEditDone:v=>s(FC({server:t,value:v})),placeholder:"*"}),jr.createElement("p",null,"Listen Port"),jr.createElement(gt,{className:"mode-reverse-input",content:String(t.listen_port||""),onEditDone:v=>s(BC({server:t,value:v})),placeholder:"8080"})),e&&jr.createElement("i",{className:"fa fa-fw fa-trash fa-lg","aria-hidden":"true",onClick:h})),jr.createElement(ui,{error:d,backendState:n}))}i(XU,"ReverseToggleRow");var Pi=pe(Te());function yE(){let e=me(s=>s.modes.transparent),t=me(s=>s.backendState.servers),n=e.map(s=>Pi.createElement(QU,{key:s.ui_id,server:s,backendState:t[y0(s)]}));return Pi.createElement("div",null,Pi.createElement("h4",{className:"mode-title"},"Transparent Proxy"),Pi.createElement("p",{className:"mode-description"},"You"," ",Pi.createElement("a",{href:"https://docs.mitmproxy.org/stable/howto-transparent/",style:{textDecoration:"underline",color:"inherit"}},"configure your routing table")," ","to send traffic through mitmproxy."),n)}i(yE,"Transparent");function QU({server:e,backendState:t}){let n=Be(),s=e.error||t?.last_exception||void 0;return Pi.createElement("div",null,Pi.createElement(ci,{value:e.active,label:"Run Transparent Proxy",onChange:()=>n(UC({server:e,value:!e.active}))},Pi.createElement(fi,{iconClass:"fa fa-cog"},Pi.createElement("h4",null,"Advanced Configuration"),Pi.createElement("p",null,"Listen Host"),Pi.createElement(gt,{className:"mode-input",content:e.listen_host||"",onEditDone:l=>n(WC({server:e,value:l}))}),Pi.createElement("p",null,"Listen Port"),Pi.createElement(gt,{className:"mode-input",content:e.listen_port?e.listen_port.toString():"",placeholder:"8080",onEditDone:l=>n($C({server:e,value:parseInt(l)}))}))),Pi.createElement(ui,{error:s,backendState:t}))}i(QU,"TransparentRow");var Zi=pe(Te());function wE(){let e=me(s=>s.modes.socks),t=me(s=>s.backendState.servers),n=e.map(s=>Zi.createElement(JU,{key:s.ui_id,server:s,backendState:t[w0(s)]}));return Zi.createElement("div",null,Zi.createElement("h4",{className:"mode-title"},"SOCKS Proxy"),Zi.createElement("p",{className:"mode-description"},"You manually configure your client application or device to use a SOCKSv5 proxy."),n)}i(wE,"Socks");function JU({server:e,backendState:t}){let n=Be(),s=e.error||t?.last_exception||void 0;return Zi.createElement("div",null,Zi.createElement(ci,{value:e.active,label:"Run SOCKS Proxy",onChange:()=>n(VC({server:e,value:!e.active}))},Zi.createElement(fi,{iconClass:"fa fa-cog"},Zi.createElement("h4",null,"Advanced Configuration"),Zi.createElement("p",null,"Listen Host"),Zi.createElement(gt,{className:"mode-input",content:e.listen_host||"",onEditDone:l=>n(qC({server:e,value:l}))}),Zi.createElement("p",null,"Listen Port"),Zi.createElement(gt,{className:"mode-input",content:e.listen_port?e.listen_port.toString():"",placeholder:"8080",onEditDone:l=>n(jC({server:e,value:parseInt(l)}))}))),Zi.createElement(ui,{error:s,backendState:t}))}i(JU,"SocksRow");var Li=pe(Te());function SE(){let e=me(s=>s.modes.upstream),t=me(s=>s.backendState.servers),n=e.map(s=>Li.createElement(ZU,{key:s.ui_id,server:s,backendState:t[S0(s)]}));return Li.createElement("div",null,Li.createElement("h4",{className:"mode-title"},"Explicit HTTP(S) Proxy (With Upstream Proxy)"),Li.createElement("p",{className:"mode-description"},"All requests are forwarded to a second HTTP(S) proxy server."),n)}i(SE,"Upstream");function ZU({server:e,backendState:t}){let n=Be(),s=e.error||t?.last_exception||void 0;return Li.createElement("div",null,Li.createElement(ci,{value:e.active,label:"Run HTTP/S Proxy and forward requests to",onChange:()=>{n(KC({server:e,value:!e.active}))}},Li.createElement(gt,{className:"mode-upstream-input",content:e.destination?.toString()||"",onEditDone:l=>n(XC({server:e,value:l})),placeholder:"http://example.com:8080"}),Li.createElement(fi,{iconClass:"fa fa-cog"},Li.createElement("h4",null,"Advanced Configuration"),Li.createElement("p",null,"Listen Host"),Li.createElement(gt,{className:"mode-input",content:e.listen_host||"",onEditDone:l=>n(GC({server:e,value:l}))}),Li.createElement("p",null,"Listen Port"),Li.createElement(gt,{className:"mode-input",content:e.listen_port?e.listen_port.toString():"",placeholder:"8080",onEditDone:l=>n(YC({server:e,value:parseInt(l)}))}))),Li.createElement(ui,{error:s,backendState:t}))}i(ZU,"UpstreamRow");var eo=pe(Te());function xE(){let e=me(s=>s.modes.dns),t=me(s=>s.backendState.servers),n=e.map(s=>eo.createElement(eW,{key:s.ui_id,server:s,backendState:t[x0(s)]}));return eo.createElement("div",null,eo.createElement("h4",{className:"mode-title"},"DNS Server"),eo.createElement("p",{className:"mode-description"},"A recursive DNS resolver using the host's DNS configuration."),n)}i(xE,"Dns");function eW({server:e,backendState:t}){let n=Be(),s=e.error||t?.last_exception||void 0;return eo.createElement("div",null,eo.createElement(ci,{value:e.active,label:"Run DNS Server",onChange:()=>n(QC({server:e,value:!e.active}))},eo.createElement(fi,{iconClass:"fa fa-cog"},eo.createElement("h4",null,"Advanced Configuration"),eo.createElement("p",null,"Listen Host"),eo.createElement(gt,{className:"mode-input",content:e.listen_host||"",onEditDone:l=>n(JC({server:e,value:l}))}),eo.createElement("p",null,"Listen Port"),eo.createElement(gt,{className:"mode-input",content:e.listen_port?e.listen_port.toString():"",placeholder:"8080",onEditDone:l=>n(ZC({server:e,value:parseInt(l)}))}))),eo.createElement(ui,{error:s,backendState:t}))}i(eW,"DnsRow");function CE(){let e=me(t=>t.backendState.platform);return In.createElement("div",{className:"modes"},In.createElement("h2",null,"Intercept Traffic"),In.createElement("p",null,"Configure how you want to intercept traffic with mitmproxy."),In.createElement("div",{className:"modes-category green-left-border"},In.createElement("h3",null,"Recommended"),In.createElement("div",{className:"modes-container"},In.createElement(mE,null),e.startsWith("linux")?void 0:In.createElement(hE,null),In.createElement(gE,null),In.createElement(vE,null))),In.createElement("div",{className:"modes-category gray-left-border"},In.createElement("h3",null,"Advanced"),In.createElement("div",{className:"modes-container"},In.createElement(wE,null),In.createElement(SE,null),In.createElement(xE,null),e.startsWith("win32")?void 0:In.createElement(yE,null))))}i(CE,"Modes");function _E(){let e=me(s=>!!s.flows.byId[s.flows.selected[0]]),t=me(s=>s.flows.list.length>0),n=me(s=>s.ui.tabs.current);return Ta.createElement("div",{className:"main-view"},n===0?Ta.createElement(CE,null):Ta.createElement(Ta.Fragment,null,t?Ta.createElement(nM,null):Ta.createElement(dE,null),e&&Ta.createElement(Qm,{key:"splitter"}),e&&Ta.createElement(A_,{key:"flowDetails"})))}i(_E,"MainView");var to=pe(Te()),pO=pe(ai());var Qn=pe(Te());var rw=pe(Te());function hs({children:e}){return window.MITMWEB_STATIC?null:rw.createElement(rw.Fragment,null,e)}i(hs,"HideInStatic");var aO=Qn.memo(i(function(){let t=Be(),n=me(s=>s.flows.filter);return Qn.createElement(Yu,{className:"pull-left special",text:"File",options:{placement:"bottom-start"}},Qn.createElement("li",null,Qn.createElement(E0,{icon:"fa-folder-open",text:"\xA0Open...",onClick:s=>s.stopPropagation(),onOpenFile:s=>{t($A(s)),document.body.click()}})),Qn.createElement(li,{onClick:()=>location.replace("/flows/dump")},Qn.createElement("i",{className:"fa fa-fw fa-floppy-o"}),"\xA0Save"),Qn.createElement(li,{onClick:()=>location.replace("/flows/dump?filter="+n)},Qn.createElement("i",{className:"fa fa-fw fa-floppy-o"}),"\xA0Save filtered"),Qn.createElement(li,{onClick:()=>confirm("Delete all flows?")&&t(Gy())},Qn.createElement("i",{className:"fa fa-fw fa-trash"}),"\xA0Clear All"),Qn.createElement(hs,null,Qn.createElement($L,null),Qn.createElement("li",null,Qn.createElement("a",{href:"http://mitm.it/",target:"_blank",rel:"noreferrer"},Qn.createElement("i",{className:"fa fa-fw fa-external-link"}),"\xA0Install Certificates..."))))},"FileMenu"));var tc=pe(Te());var lO=tc.memo(i(function(){let t=me(s=>s.connection.state),n=me(s=>s.connection.message);switch(t){case"CONNECTION_INIT":return tc.createElement("span",{className:"connection-indicator init"},"connecting\u2026");case"CONNECTION_FETCHING":return tc.createElement("span",{className:"connection-indicator fetching"},"fetching data\u2026");case"CONNECTION_ESTABLISHED":return tc.createElement("span",{className:"connection-indicator established"},"connected");case"CONNECTION_ERROR":return tc.createElement("span",{className:"connection-indicator error",title:n},"connection lost");case"CONNECTION_OFFLINE":return tc.createElement("span",{className:"connection-indicator offline"},"offline")}},"ConnectionIndicator"));var nw=pe(Te());iw.title="Capture";function iw(){return nw.createElement(nw.Fragment,null)}i(iw,"CaptureMenu");var pi=pe(Te());var ms=pe(Te()),uO=pe(ai());var Bo=pe(Te());var ug=class e extends Bo.Component{static{i(this,"FilterDocs")}constructor(t,n){super(t,n),this.state={doc:e.doc}}componentDidMount(){e.xhr||(e.xhr=xt("/filter-help").then(t=>t.json()),e.xhr.catch(()=>{e.xhr=null})),this.state.doc||e.xhr.then(t=>{e.doc=t,this.setState({doc:t})})}render(){let{doc:t}=this.state;return t?Bo.default.createElement("table",{className:"table table-condensed"},Bo.default.createElement("tbody",null,t.commands.map(n=>Bo.default.createElement("tr",{key:n[1],onClick:()=>this.props.selectHandler(n[0].split(" ")[0]+" ")},Bo.default.createElement("td",null,n[0].replace(" ","\xA0")),Bo.default.createElement("td",null,n[1]))),Bo.default.createElement("tr",{key:"docs-link"},Bo.default.createElement("td",{colSpan:2},Bo.default.createElement("a",{href:"https://mitmproxy.org/docs/latest/concepts-filters/",target:"_blank",rel:"noreferrer"},Bo.default.createElement("i",{className:"fa fa-external-link"}),"\xA0 mitmproxy docs"))))):Bo.default.createElement("i",{className:"fa fa-spinner fa-spin"})}};var Uf=class extends ms.Component{constructor(n,s){super(n,s);this.inputRef=ms.default.createRef();this.state={value:this.props.value,focus:!1,mousefocus:!1},this.onChange=this.onChange.bind(this),this.onFocus=this.onFocus.bind(this),this.onBlur=this.onBlur.bind(this),this.onKeyDown=this.onKeyDown.bind(this),this.onMouseEnter=this.onMouseEnter.bind(this),this.onMouseLeave=this.onMouseLeave.bind(this),this.selectFilter=this.selectFilter.bind(this)}static{i(this,"FilterInput")}UNSAFE_componentWillReceiveProps(n){this.setState({value:n.value})}isValid(n){try{return n&&vf.parse(n),!0}catch{return!1}}getDesc(){if(!this.state.value)return ms.default.createElement(ug,{selectHandler:this.selectFilter});try{return vf.parse(this.state.value).desc}catch(n){return""+n}}onChange(n){let s=n.target.value;this.setState({value:s}),this.isValid(s)&&this.props.onChange(s)}onFocus(){this.setState({focus:!0})}onBlur(){this.setState({focus:!1})}onMouseEnter(){this.setState({mousefocus:!0})}onMouseLeave(){this.setState({mousefocus:!1})}onKeyDown(n){(n.key==="Escape"||n.key==="Enter")&&(this.blur(),this.setState({mousefocus:!1})),n.stopPropagation()}selectFilter(n){this.setState({value:n}),this.inputRef.current?.focus()}blur(){this.inputRef.current?.blur()}select(){this.inputRef.current?.select()}render(){let{type:n,color:s,placeholder:l}=this.props,{value:h,focus:d,mousefocus:v}=this.state;return ms.default.createElement("div",{className:(0,uO.default)("filter-input input-group",{"has-error":!this.isValid(h)})},ms.default.createElement("span",{className:"input-group-addon"},ms.default.createElement("i",{className:"fa fa-fw fa-"+n,style:{color:s}})),ms.default.createElement("input",{type:"text",ref:this.inputRef,placeholder:l,className:"form-control",value:h,onChange:this.onChange,onFocus:this.onFocus,onBlur:this.onBlur,onKeyDown:this.onKeyDown}),(d||v)&&ms.default.createElement("div",{className:"popover bottom",onMouseEnter:this.onMouseEnter,onMouseLeave:this.onMouseLeave},ms.default.createElement("div",{className:"arrow"}),ms.default.createElement("div",{className:"popover-content"},this.getDesc())))}};ow.title="Flow List";function ow(){return pi.createElement("div",{className:"main-menu"},pi.createElement("div",{className:"menu-group"},pi.createElement("div",{className:"menu-content"},pi.createElement(nW,null),pi.createElement(iW,null)),pi.createElement("div",{className:"menu-legend"},"Find")),pi.createElement("div",{className:"menu-group"},pi.createElement("div",{className:"menu-content"},pi.createElement(rW,null),pi.createElement(oW,null)),pi.createElement("div",{className:"menu-legend"},"Intercept")))}i(ow,"FlowListMenu");function rW(){let e=Be(),t=me(n=>n.options.intercept);return pi.createElement(Uf,{value:t||"",placeholder:"Intercept",type:"pause",color:"hsl(208, 56%, 53%)",onChange:n=>e(gp("intercept",n))})}i(rW,"InterceptInput");function nW(){let e=Be(),t=me(n=>n.flows.filter);return pi.createElement(Uf,{value:t||"",placeholder:"Search",type:"search",color:"black",onChange:n=>e(Uy(n))})}i(nW,"FlowFilterInput");function iW(){let e=Be(),t=me(n=>n.flows.highlight);return pi.createElement(Uf,{value:t||"",placeholder:"Highlight",type:"tag",color:"hsl(48, 100%, 50%)",onChange:n=>e(Wy(n))})}i(iW,"HighlightInput");function oW(){let e=Be();return pi.createElement(Or,{className:"btn-sm",title:"[a]ccept all",icon:"fa-forward text-success",onClick:()=>e($y())},"Resume All")}i(oW,"ResumeAll");var un=pe(Te());var Wf=pe(Te());function EE({value:e,onChange:t,children:n}){return Wf.createElement("div",{className:"menu-entry"},Wf.createElement("label",null,Wf.createElement("input",{type:"checkbox",checked:e,onChange:t}),n))}i(EE,"MenuToggle");function sw({name:e,children:t}){let n=Be(),s=me(l=>l.options[e]);return Wf.createElement(EE,{value:!!s,onChange:()=>n(gp(e,!s))},t)}i(sw,"OptionsToggle");function cO(){let e=Be(),t=me(n=>n.eventLog.visible);return Wf.createElement(EE,{value:t,onChange:()=>e(mp())},"Display Event Log")}i(cO,"EventlogToggle");function fO(){let e=Be(),t=me(n=>n.commandBar.visible);return Wf.createElement(EE,{value:t,onChange:()=>e(f0())},"Display Command Bar")}i(fO,"CommandBarToggle");var bE=pe(Te());function TE({children:e,resource:t}){let n=`https://docs.mitmproxy.org/stable/${t}`;return bE.createElement("a",{target:"_blank",href:n,rel:"noreferrer"},e||bE.createElement("i",{className:"fa fa-question-circle"}))}i(TE,"DocsLink");aw.title="Options";function aw(){let e=Be(),t=i(()=>qA("OptionModal"),"openOptions");return un.createElement("div",null,un.createElement(hs,null,un.createElement("div",{className:"menu-group"},un.createElement("div",{className:"menu-content"},un.createElement(Or,{title:"Open Options",icon:"fa-cogs text-primary",onClick:()=>e(t())},"Edit Options ",un.createElement("sup",null,"alpha"))),un.createElement("div",{className:"menu-legend"},"Options Editor")),un.createElement("div",{className:"menu-group"},un.createElement("div",{className:"menu-content"},un.createElement(sw,{name:"anticache"},"Strip cache headers"," ",un.createElement(TE,{resource:"overview-features/#anticache"})),un.createElement(sw,{name:"showhost"},"Use host header for display"),un.createElement(sw,{name:"ssl_insecure"},"Don't verify server certificates")),un.createElement("div",{className:"menu-legend"},"Quick Options"))),un.createElement("div",{className:"menu-group"},un.createElement("div",{className:"menu-content"},un.createElement(cO,null),un.createElement(fO,null)),un.createElement("div",{className:"menu-legend"},"View Options")))}i(aw,"OptionMenu");var ft=pe(Te());var Dp=i(async(e,t)=>{let n=(async()=>{let s=await gf("export",t,`@${e.id}`);if(s.value)return s.value;throw s.error?s.error:s})();try{await AA(n)}catch(s){alert(s)}},"copy");uw.title="Flow";function uw(){let e=Be(),t=me(n=>n.flows.byId[n.flows.selected[0]]);return t?ft.createElement("div",{className:"flow-menu"},ft.createElement(hs,null,ft.createElement("div",{className:"menu-group"},ft.createElement("div",{className:"menu-content"},ft.createElement(Or,{title:"[r]eplay flow",icon:"fa-repeat text-primary",onClick:()=>e(up(t)),disabled:!zy(t)},"Replay"),ft.createElement(Or,{title:"[D]uplicate flow",icon:"fa-copy text-info",onClick:()=>e(jy(t))},"Duplicate"),ft.createElement(Or,{disabled:!t||!t.modified,title:"revert changes to flow [V]",icon:"fa-history text-warning",onClick:()=>e(Ky(t))},"Revert"),ft.createElement(Or,{title:"[d]elete flow",icon:"fa-trash text-danger",onClick:()=>e(qy(t))},"Delete"),ft.createElement(uW,{flow:t})),ft.createElement("div",{className:"menu-legend"},"Flow Modification"))),ft.createElement("div",{className:"menu-group"},ft.createElement("div",{className:"menu-content"},ft.createElement(sW,{flow:t}),ft.createElement(aW,{flow:t})),ft.createElement("div",{className:"menu-legend"},"Export")),ft.createElement(hs,null,ft.createElement("div",{className:"menu-group"},ft.createElement("div",{className:"menu-content"},ft.createElement(Or,{disabled:!t||!t.intercepted,title:"[a]ccept intercepted flow",icon:"fa-play text-success",onClick:()=>e(lp(t))},"Resume"),ft.createElement(Or,{disabled:!t||!t.intercepted,title:"kill intercepted flow [x]",icon:"fa-times text-danger",onClick:()=>e(Vy(t))},"Abort")),ft.createElement("div",{className:"menu-legend"},"Interception")))):ft.createElement("div",null)}i(uw,"FlowMenu");var lw=i(e=>{let t=window.open(e,"_blank","noopener,noreferrer");t&&(t.opener=null)},"openInNewTab");function sW({flow:e}){if(e.type!=="http")return ft.createElement(Or,{icon:"fa-download",onClick:()=>0,disabled:!0},"Download");if(e.request.contentLength&&!e.response?.contentLength)return ft.createElement(Or,{icon:"fa-download",onClick:()=>lw(On.getContentURL(e,e.request))},"Download");if(e.response){let t=e.response;if(!e.request.contentLength&&e.response.contentLength)return ft.createElement(Or,{icon:"fa-download",onClick:()=>lw(On.getContentURL(e,t))},"Download");if(e.request.contentLength&&e.response.contentLength)return ft.createElement(Yu,{text:ft.createElement(Or,{icon:"fa-download",onClick:()=>1},"Download\u25BE"),options:{placement:"bottom-start"}},ft.createElement(li,{onClick:()=>lw(On.getContentURL(e,e.request))},"Download request"),ft.createElement(li,{onClick:()=>lw(On.getContentURL(e,t))},"Download response"))}return null}i(sW,"DownloadButton");function aW({flow:e}){return ft.createElement(Yu,{className:"",text:ft.createElement(Or,{title:"Export flow.",icon:"fa-clone",onClick:()=>1,disabled:e.type!=="http"},"Export\u25BE"),options:{placement:"bottom-start"}},ft.createElement(li,{onClick:()=>Dp(e,"raw_request")},"Copy raw request"),ft.createElement(li,{onClick:()=>Dp(e,"raw_response")},"Copy raw response"),ft.createElement(li,{onClick:()=>Dp(e,"raw")},"Copy raw request and response"),ft.createElement(li,{onClick:()=>Dp(e,"curl")},"Copy as cURL"),ft.createElement(li,{onClick:()=>Dp(e,"httpie")},"Copy as HTTPie"))}i(aW,"ExportButton");var lW={":red_circle:":"\u{1F534}",":orange_circle:":"\u{1F7E0}",":yellow_circle:":"\u{1F7E1}",":green_circle:":"\u{1F7E2}",":large_blue_circle:":"\u{1F535}",":purple_circle:":"\u{1F7E3}",":brown_circle:":"\u{1F7E4}"};function uW({flow:e}){let t=Be();return ft.createElement(Yu,{className:"",text:ft.createElement(Or,{title:"mark flow",icon:"fa-paint-brush text-success",onClick:()=>1},"Mark\u25BE"),options:{placement:"bottom-start"}},ft.createElement(li,{onClick:()=>t(si(e,{marked:""}))},"\u26AA (no marker)"),Object.entries(lW).map(([n,s])=>ft.createElement(li,{key:n,onClick:()=>t(si(e,{marked:n}))},s," ",n.replace(/[:_]/g," "))))}i(uW,"MarkButton");var dO={0:iw,1:ow,2:aw,3:uw};function kE(){let e=Be(),t=me(k=>k.ui.tabs.current),n=me(k=>k.flows.selected.filter(R=>R in k.flows.byId),Mo),[s,l]=(0,to.useState)(!1),h=me(k=>k.flows.list.length>0),d=me(k=>k.ui.tabs.isInitial),v=[0,1,2];n.length>0&&v.push(3),(0,to.useEffect)(()=>{h&&d&&e(Im(1))},[h]),(0,to.useEffect)(()=>{n.length>0&&!s?(e(Im(3)),l(!0)):n.length===0&&(s&&l(!1),t===3&&e(Im(1)))},[n,s,t]);function S(k,R){R.preventDefault(),e(Im(k))}i(S,"handleClick");let b=dO[t];return to.default.createElement("header",null,to.default.createElement("nav",{className:"nav-tabs nav-tabs-lg"},to.default.createElement(aO,null),v.map(k=>to.default.createElement("a",{key:k,href:"#",className:(0,pO.default)({active:k===t}),onClick:R=>S(k,R)},dO[k].title)),to.default.createElement(hs,null,to.default.createElement(lO,null))),to.default.createElement("div",null,to.default.createElement(b,null)))}i(kE,"Header");var nt=pe(Te()),hO=pe(ai());var cw=function(){"use strict";function e(s,l){function h(){this.constructor=s}i(h,"ctor"),h.prototype=l.prototype,s.prototype=new h}i(e,"peg$subclass");function t(s,l,h,d){this.message=s,this.expected=l,this.found=h,this.location=d,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,t)}i(t,"peg$SyntaxError"),e(t,Error);function n(s){var l=arguments.length>1?arguments[1]:{},h=this,d={},v={Expr:Bn},S=Bn,b=i(function(Y,ee){return[Y,...ee]},"peg$c0"),k=i(function(Y){return[Y]},"peg$c1"),R=i(function(){return""},"peg$c2"),I={type:"other",description:"string"},z='"',q={type:"literal",value:'"',description:'"\\""'},Q=i(function(Y){return Y.join("")},"peg$c6"),ne="'",D={type:"literal",value:"'",description:`"'"`},L=/^["\\]/,B={type:"class",value:'["\\\\]',description:'["\\\\]'},j={type:"any",description:"any character"},re=i(function(Y){return Y},"peg$c12"),Z="\\",oe={type:"literal",value:"\\",description:'"\\\\"'},he=/^['\\]/,Re={type:"class",value:"['\\\\]",description:"['\\\\]"},Ee=/^['"\\]/,Ye={type:"class",value:`['"\\\\]`,description:`['"\\\\]`},tt="n",xe={type:"literal",value:"n",description:'"n"'},Xe=i(function(){return` +`},"peg$c21"),je="r",Qe={type:"literal",value:"r",description:'"r"'},ot=i(function(){return"\r"},"peg$c24"),It="t",At={type:"literal",value:"t",description:'"t"'},cn=i(function(){return" "},"peg$c27"),fn={type:"other",description:"whitespace"},gr=/^[ \t\n\r]/,Wt={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},vr={type:"other",description:"control character"},yr=/^[|&!()~"]/,Gt={type:"class",value:'[|&!()~"]',description:'[|&!()~"]'},Ft={type:"other",description:"optional whitespace"},se=0,Ue=0,Kr=[{line:1,column:1,seenCR:!1}],Zt=0,st=[],Fe=0,Fn;if("startRule"in l){if(!(l.startRule in v))throw new Error(`Can't start parsing from rule "`+l.startRule+'".');S=v[l.startRule]}function En(){return s.substring(Ue,se)}i(En,"text");function no(){return fr(Ue,se)}i(no,"location");function Ho(Y){throw io(null,[{type:"other",description:Y}],s.substring(Ue,se),fr(Ue,se))}i(Ho,"expected");function lt(Y){throw io(Y,null,s.substring(Ue,se),fr(Ue,se))}i(lt,"error");function wr(Y){var ee=Kr[Y],Ce,Me;if(ee)return ee;for(Ce=Y-1;!Kr[Ce];)Ce--;for(ee=Kr[Ce],ee={line:ee.line,column:ee.column,seenCR:ee.seenCR};CeZt&&(Zt=se,st=[]),st.push(Y))}i(pt,"peg$fail");function io(Y,ee,Ce,Me){function Tl(Xr){var Yt=1;for(Xr.sort(function(Mt,Pt){return Mt.descriptionPt.description?1:0});Yt1?Pt.slice(0,-1).join(", ")+" or "+Pt[Xr.length-1]:Pt[0],dn=Yt?'"'+Mt(Yt)+'"':"end of input","Expected "+Na+" but "+dn+" found."}return i(ze,"buildMessage"),ee!==null&&Tl(ee),new t(Y!==null?Y:ze(ee,Ce),ee,Ce,Me)}i(io,"peg$buildException");function Bn(){var Y,ee,Ce,Me;if(Y=se,ee=Mi(),ee!==d){if(Ce=[],Me=Hn(),Me!==d)for(;Me!==d;)Ce.push(Me),Me=Hn();else Ce=d;Ce!==d?(Me=Bn(),Me!==d?(Ue=Y,ee=b(ee,Me),Y=ee):(se=Y,Y=d)):(se=Y,Y=d)}else se=Y,Y=d;if(Y===d&&(Y=se,ee=Mi(),ee!==d&&(Ue=Y,ee=k(ee)),Y=ee,Y===d)){for(Y=se,ee=[],Ce=Hn();Ce!==d;)ee.push(Ce),Ce=Hn();ee!==d&&(Ue=Y,ee=R()),Y=ee}return Y}i(Bn,"peg$parseExpr");function Mi(){var Y,ee,Ce,Me;if(Fe++,Y=se,s.charCodeAt(se)===34?(ee=z,se++):(ee=d,Fe===0&&pt(q)),ee!==d){for(Ce=[],Me=Gr();Me!==d;)Ce.push(Me),Me=Gr();Ce!==d?(s.charCodeAt(se)===34?(Me=z,se++):(Me=d,Fe===0&&pt(q)),Me!==d?(Ue=Y,ee=Q(Ce),Y=ee):(se=Y,Y=d)):(se=Y,Y=d)}else se=Y,Y=d;if(Y===d){if(Y=se,s.charCodeAt(se)===39?(ee=ne,se++):(ee=d,Fe===0&&pt(D)),ee!==d){for(Ce=[],Me=Yr();Me!==d;)Ce.push(Me),Me=Yr();Ce!==d?(s.charCodeAt(se)===39?(Me=ne,se++):(Me=d,Fe===0&&pt(D)),Me!==d?(Ue=Y,ee=Q(Ce),Y=ee):(se=Y,Y=d)):(se=Y,Y=d)}else se=Y,Y=d;if(Y===d){if(Y=se,ee=se,Fe++,Ce=so(),Fe--,Ce===d?ee=void 0:(se=ee,ee=d),ee!==d){if(Ce=[],Me=oo(),Me!==d)for(;Me!==d;)Ce.push(Me),Me=oo();else Ce=d;Ce!==d?(Ue=Y,ee=Q(Ce),Y=ee):(se=Y,Y=d)}else se=Y,Y=d;if(Y===d){if(Y=se,s.charCodeAt(se)===34?(ee=z,se++):(ee=d,Fe===0&&pt(q)),ee!==d){for(Ce=[],Me=Gr();Me!==d;)Ce.push(Me),Me=Gr();Ce!==d?(Ue=Y,ee=Q(Ce),Y=ee):(se=Y,Y=d)}else se=Y,Y=d;if(Y===d)if(Y=se,s.charCodeAt(se)===39?(ee=ne,se++):(ee=d,Fe===0&&pt(D)),ee!==d){for(Ce=[],Me=Yr();Me!==d;)Ce.push(Me),Me=Yr();Ce!==d?(Ue=Y,ee=Q(Ce),Y=ee):(se=Y,Y=d)}else se=Y,Y=d}}}return Fe--,Y===d&&(ee=d,Fe===0&&pt(I)),Y}i(Mi,"peg$parseStringLiteral");function Gr(){var Y,ee,Ce;return Y=se,ee=se,Fe++,L.test(s.charAt(se))?(Ce=s.charAt(se),se++):(Ce=d,Fe===0&&pt(B)),Fe--,Ce===d?ee=void 0:(se=ee,ee=d),ee!==d?(s.length>se?(Ce=s.charAt(se),se++):(Ce=d,Fe===0&&pt(j)),Ce!==d?(Ue=Y,ee=re(Ce),Y=ee):(se=Y,Y=d)):(se=Y,Y=d),Y===d&&(Y=se,s.charCodeAt(se)===92?(ee=Z,se++):(ee=d,Fe===0&&pt(oe)),ee!==d?(Ce=hi(),Ce!==d?(Ue=Y,ee=re(Ce),Y=ee):(se=Y,Y=d)):(se=Y,Y=d)),Y}i(Gr,"peg$parseDoubleStringChar");function Yr(){var Y,ee,Ce;return Y=se,ee=se,Fe++,he.test(s.charAt(se))?(Ce=s.charAt(se),se++):(Ce=d,Fe===0&&pt(Re)),Fe--,Ce===d?ee=void 0:(se=ee,ee=d),ee!==d?(s.length>se?(Ce=s.charAt(se),se++):(Ce=d,Fe===0&&pt(j)),Ce!==d?(Ue=Y,ee=re(Ce),Y=ee):(se=Y,Y=d)):(se=Y,Y=d),Y===d&&(Y=se,s.charCodeAt(se)===92?(ee=Z,se++):(ee=d,Fe===0&&pt(oe)),ee!==d?(Ce=hi(),Ce!==d?(Ue=Y,ee=re(Ce),Y=ee):(se=Y,Y=d)):(se=Y,Y=d)),Y}i(Yr,"peg$parseSingleStringChar");function oo(){var Y,ee,Ce;return Y=se,ee=se,Fe++,Ce=Hn(),Fe--,Ce===d?ee=void 0:(se=ee,ee=d),ee!==d?(s.length>se?(Ce=s.charAt(se),se++):(Ce=d,Fe===0&&pt(j)),Ce!==d?(Ue=Y,ee=re(Ce),Y=ee):(se=Y,Y=d)):(se=Y,Y=d),Y}i(oo,"peg$parseUnquotedStringChar");function hi(){var Y,ee;return Ee.test(s.charAt(se))?(Y=s.charAt(se),se++):(Y=d,Fe===0&&pt(Ye)),Y===d&&(Y=se,s.charCodeAt(se)===110?(ee=tt,se++):(ee=d,Fe===0&&pt(xe)),ee!==d&&(Ue=Y,ee=Xe()),Y=ee,Y===d&&(Y=se,s.charCodeAt(se)===114?(ee=je,se++):(ee=d,Fe===0&&pt(Qe)),ee!==d&&(Ue=Y,ee=ot()),Y=ee,Y===d&&(Y=se,s.charCodeAt(se)===116?(ee=It,se++):(ee=d,Fe===0&&pt(At)),ee!==d&&(Ue=Y,ee=cn()),Y=ee))),Y}i(hi,"peg$parseEscapeSequence");function Hn(){var Y,ee;return Fe++,gr.test(s.charAt(se))?(Y=s.charAt(se),se++):(Y=d,Fe===0&&pt(Wt)),Fe--,Y===d&&(ee=d,Fe===0&&pt(fn)),Y}i(Hn,"peg$parsews");function so(){var Y,ee;return Fe++,yr.test(s.charAt(se))?(Y=s.charAt(se),se++):(Y=d,Fe===0&&pt(Gt)),Fe--,Y===d&&(ee=d,Fe===0&&pt(vr)),Y}i(so,"peg$parsecc");function bl(){var Y,ee;for(Fe++,Y=[],ee=Hn();ee!==d;)Y.push(ee),ee=Hn();return Fe--,Y===d&&(ee=d,Fe===0&&pt(Ft)),Y}if(i(bl,"peg$parse__"),Fn=S(),Fn!==d&&se===s.length)return Fn;throw Fn!==d&&se{t&&t.current.addEventListener("DOMNodeInserted",n=>{let s=n.currentTarget;s.scroll({top:s.scrollHeight,behavior:"auto"})})},[]),nt.default.createElement("div",{className:"command-result",ref:t},e.map((n,s)=>nt.default.createElement("div",{key:s},nt.default.createElement("div",null,nt.default.createElement("strong",null,"$ ",n.command)),n.result)))}i(cW,"Results");function fW({nextArgs:e,currentArg:t,help:n,description:s,availableCommands:l}){let h=[];for(let d=0;d0&&nt.default.createElement("div",null,nt.default.createElement("strong",null,"Argument suggestion:")," ",h),n?.includes("->")&&nt.default.createElement("div",null,nt.default.createElement("strong",null,"Signature help: "),n),s&&nt.default.createElement("div",null,"# ",s),nt.default.createElement("div",null,nt.default.createElement("strong",null,"Available Commands: "),nt.default.createElement("p",{className:"available-commands"},JSON.stringify(l)))))}i(fW,"CommandHelp");function AE(){let[e,t]=(0,nt.useState)(""),[n,s]=(0,nt.useState)(""),[l,h]=(0,nt.useState)(0),[d,v]=(0,nt.useState)([]),[S,b]=(0,nt.useState)([]),[k,R]=(0,nt.useState)({}),[I,z]=(0,nt.useState)([]),[q,Q]=(0,nt.useState)(0),[ne,D]=(0,nt.useState)(""),[L,B]=(0,nt.useState)(""),[j,re]=(0,nt.useState)([]),[Z,oe]=(0,nt.useState)([]),[he,Re]=(0,nt.useState)(void 0);(0,nt.useEffect)(()=>{xt("/commands",{method:"GET"}).then(Xe=>Xe.json()).then(Xe=>{R(Xe),v(NE(Xe)),b(Object.keys(Xe))}).catch(Xe=>console.error(Xe))},[]),(0,nt.useEffect)(()=>{gf("commands.history.get").then(Xe=>{oe(Xe.value)}).catch(Xe=>console.error(Xe))},[]);let Ee=i((Xe,je)=>{let Qe=cw.parse(je),ot=cw.parse(Xe);D(k[Qe[0]]?.signature_help),B(k[Qe[0]]?.help||""),v(NE(k,ot[0])),b(NE(k,Qe[0]));let It=k[Qe[0]]?.parameters.map(At=>At.name);It&&(z([Qe[0],...It]),Q(Qe.length-1))},"parseCommand"),Ye=i(Xe=>{t(Xe.target.value),s(Xe.target.value),h(0)},"onChange"),tt=i(Xe=>{if(Xe.key==="Enter"){let[je,...Qe]=cw.parse(e);oe([...Z,e]),gf("commands.history.add",e).catch(()=>0),xt.post(`/commands/${je}`,{arguments:Qe}).then(ot=>ot.json()).then(ot=>{Re(void 0),z([]),re([...j,{command:e,result:JSON.stringify(ot.value||ot.error)}])}).catch(ot=>{Re(void 0),z([]),re([...j,{command:e,result:ot.toString()}])}),D(""),B(""),t(""),s(""),h(0),v(S)}if(Xe.key==="ArrowUp"){let je;he===void 0?je=Z.length-1:je=Math.max(0,he-1),t(Z[je]),s(Z[je]),Re(je)}if(Xe.key==="ArrowDown"){if(he===void 0)return;if(he==Z.length-1)t(""),s(""),Re(void 0);else{let je=he+1;t(Z[je]),s(Z[je]),Re(je)}}Xe.key==="Tab"&&(t(d[l]),h((l+1)%d.length),Xe.preventDefault()),Xe.stopPropagation()},"onKeyDown"),xe=i(Xe=>{if(!e){b(Object.keys(k));return}Ee(n,e),Xe.stopPropagation()},"onKeyUp");return nt.default.createElement("div",{className:"command"},nt.default.createElement("div",{className:"command-title"},"Command Result"),nt.default.createElement(cW,{results:j}),nt.default.createElement(fW,{nextArgs:I,currentArg:q,help:ne,description:L,availableCommands:S}),nt.default.createElement("div",{className:(0,hO.default)("command-input input-group")},nt.default.createElement("span",{className:"input-group-addon"},nt.default.createElement("i",{className:"fa fa-fw fa-terminal"})),nt.default.createElement("input",{type:"text",placeholder:"Enter command",className:"form-control",value:e||"",onChange:Ye,onKeyDown:tt,onKeyUp:xe})))}i(AE,"CommandBar");var El=pe(Te());var PE=pe(Te());function LE({checked:e,onToggle:t,text:n}){return PE.default.createElement("div",{className:"btn btn-toggle "+(e?"btn-primary":"btn-default"),onClick:t},PE.default.createElement("i",{className:"fa fa-fw "+(e?"fa-check-square-o":"fa-square-o")}),"\xA0",n)}i(LE,"ToggleButton");var ka=pe(Te()),ME=pe(CO());var cg=class extends ka.Component{constructor(n){super(n);this.viewport=ka.default.createRef();this.heights={},this.state={vScroll:Df()},this.onViewportUpdate=this.onViewportUpdate.bind(this)}static{i(this,"EventLogList")}static{this.propTypes={events:ME.default.array.isRequired,rowHeight:ME.default.number}}static{this.defaultProps={rowHeight:18}}componentDidMount(){window.addEventListener("resize",this.onViewportUpdate),this.onViewportUpdate()}componentWillUnmount(){window.removeEventListener("resize",this.onViewportUpdate)}getSnapshotBeforeUpdate(){return Jm(this.viewport)}componentDidUpdate(n,s,l){l&&$0(this.viewport),this.onViewportUpdate()}onViewportUpdate(){let n=this.viewport.current,s=Df({itemCount:this.props.events.length,rowHeight:this.props.rowHeight,viewportTop:n.scrollTop,viewportHeight:n.offsetHeight,itemHeights:this.props.events.map(l=>this.heights[l.id])});Mo(this.state.vScroll,s)||this.setState({vScroll:s})}setHeight(n,s){if(s&&!this.heights[n]){let l=s.offsetHeight;this.heights[n]!==l&&(this.heights[n]=l,this.onViewportUpdate())}}render(){let{vScroll:n}=this.state,{events:s}=this.props;return ka.default.createElement("pre",{ref:this.viewport,onScroll:this.onViewportUpdate},ka.default.createElement("div",{style:{height:n.paddingTop}}),s.slice(n.start,n.end).map(l=>ka.default.createElement("div",{key:l.id,ref:h=>this.setHeight(l.id,h)},ka.default.createElement(hW,{event:l}),l.message)),ka.default.createElement("div",{style:{height:n.paddingBottom}}))}};function hW({event:e}){let t={web:"html5",debug:"bug",warn:"exclamation-triangle",error:"ban"}[e.level]||"info";return ka.default.createElement("i",{className:`fa fa-fw fa-${t}`})}i(hW,"LogIcon");var OE=class extends El.Component{static{i(this,"PureEventLog")}static{this.defaultProps={defaultHeight:200}}constructor(t,n){super(t,n),this.state={height:this.props.defaultHeight},this.onDragStart=this.onDragStart.bind(this),this.onDragMove=this.onDragMove.bind(this),this.onDragStop=this.onDragStop.bind(this)}onDragStart(t){t.preventDefault(),this.dragStart=this.state.height+t.pageY,window.addEventListener("mousemove",this.onDragMove),window.addEventListener("mouseup",this.onDragStop),window.addEventListener("dragend",this.onDragStop)}onDragMove(t){t.preventDefault(),this.setState({height:this.dragStart-t.pageY})}onDragStop(t){t.preventDefault(),window.removeEventListener("mousemove",this.onDragMove)}render(){let{height:t}=this.state,{filters:n,events:s,toggleFilter:l,close:h}=this.props;return El.default.createElement("div",{className:"eventlog",style:{height:t}},El.default.createElement("div",{onMouseDown:this.onDragStart},"Eventlog",El.default.createElement("div",{className:"pull-right"},Object.values(pC).map(d=>El.default.createElement(LE,{key:d,text:d,checked:n[d],onToggle:()=>l(d)})),El.default.createElement("i",{onClick:h,className:"fa fa-close"}))),El.default.createElement(cg,{events:s}))}},_O=Wu(e=>({filters:e.eventLog.filters,events:e.eventLog.view}),{close:mp,toggleFilter:PP})(OE);var _n=pe(Te());function RE(){let e=me(D=>D.backendState.version),{mode:t,intercept:n,showhost:s,upstream_cert:l,rawtcp:h,http2:d,websocket:v,anticache:S,anticomp:b,stickyauth:k,stickycookie:R,stream_large_bodies:I,listen_host:z,listen_port:q,server:Q,ssl_insecure:ne}=me(D=>D.options);return _n.createElement("footer",null,t&&(t.length!==1||t[0]!=="regular")&&_n.createElement("span",{className:"label label-success"},t.join(",")),n&&_n.createElement("span",{className:"label label-success"},"Intercept: ",n),ne&&_n.createElement("span",{className:"label label-danger"},"ssl_insecure"),s&&_n.createElement("span",{className:"label label-success"},"showhost"),!l&&_n.createElement("span",{className:"label label-success"},"no-upstream-cert"),!h&&_n.createElement("span",{className:"label label-success"},"no-raw-tcp"),!d&&_n.createElement("span",{className:"label label-success"},"no-http2"),!v&&_n.createElement("span",{className:"label label-success"},"no-websocket"),S&&_n.createElement("span",{className:"label label-success"},"anticache"),b&&_n.createElement("span",{className:"label label-success"},"anticomp"),k&&_n.createElement("span",{className:"label label-success"},"stickyauth: ",k),R&&_n.createElement("span",{className:"label label-success"},"stickycookie: ",R),I&&_n.createElement("span",{className:"label label-success"},"stream: ",Iy(I)),_n.createElement("div",{className:"pull-right"},_n.createElement(hs,null,Q&&_n.createElement("span",{className:"label label-primary",title:"HTTP Proxy Server Address"},z||"*",":",q||8080)),_n.createElement("span",{className:"label label-default",title:"Mitmproxy Version"},"mitmproxy ",e)))}i(RE,"Footer");var HE=pe(Te());var BE=pe(Te());var Ip=pe(Te());function DE({children:e}){return Ip.createElement("div",null,Ip.createElement("div",{className:"modal-backdrop fade in"}),Ip.createElement("div",{className:"modal modal-visible",id:"optionsModal",tabIndex:-1,role:"dialog","aria-labelledby":"options"},Ip.createElement("div",{className:"modal-dialog modal-lg",role:"document"},Ip.createElement("div",{className:"modal-content"},e))))}i(DE,"ModalLayout");var Dr=pe(Te());var fg=pe(bm());var ro=pe(Te());var kO=pe(ai());var mW=i(e=>{e.key!=="Escape"&&e.stopPropagation()},"stopPropagation");function NO({value:e,onChange:t,...n}){return ro.default.createElement("div",{className:"checkbox"},ro.default.createElement("label",null,ro.default.createElement("input",{type:"checkbox",checked:e,onChange:s=>t(s.target.checked),...n}),"Enable"))}i(NO,"BooleanOption");function EO({value:e,onChange:t,...n}){return ro.default.createElement("input",{type:"text",value:e||"",onChange:s=>t(s.target.value),...n})}i(EO,"StringOption");function bO(e){return i(function({onChange:n,...s}){return ro.default.createElement(e,{onChange:l=>n(l||null),...s})},"OptionalWrapper")}i(bO,"Optional");function TO({value:e,onChange:t,...n}){return ro.default.createElement("input",{type:"number",value:e,onChange:s=>t(parseInt(s.target.value)),...n})}i(TO,"NumberOption");function gW({value:e,onChange:t,choices:n,...s}){return ro.default.createElement("select",{onChange:l=>t(l.target.value),value:e,...s},n.map(l=>ro.default.createElement("option",{key:l,value:l},l)))}i(gW,"ChoicesOption");function vW({value:e,onChange:t,...n}){let s=Math.max(e.length,1),[l,h]=ro.default.useState(e.join(` +`));return ro.default.createElement("textarea",{rows:s,value:l,onChange:i(v=>{let S=v.target.value;h(S),t(S.split(` +`).map(b=>b.trim()).filter(b=>b!==""))},"handleChange"),...n})}i(vW,"StringSequenceOption");var yW={bool:NO,str:EO,int:TO,"optional str":bO(EO),"optional int":bO(TO),"sequence of str":vW};function wW({choices:e,type:t,value:n,onChange:s,name:l,error:h}){let d,v={onChange:s,value:n};if(e)d=gW,v.choices=e;else if(d=yW[t],!d)throw`unknown option type ${t}`;return d!==NO&&(v.className="form-control"),ro.default.createElement("div",{className:(0,kO.default)({"has-error":h})},ro.default.createElement(d,{name:l,onKeyDown:mW,...v}))}i(wW,"PureOption");function IE({name:e}){let t=Be(),n=me(d=>d.options_meta[e]?.choices),s=me(d=>d.options_meta[e]?.type),l=me(d=>{let v=d.ui.optionsEditor[e];return v?v.value:d.options_meta[e]?.value}),h=me(d=>d.ui.optionsEditor[e]?.error);return ro.default.createElement(wW,{name:e,choices:n,type:s,value:l,error:h,onChange:d=>t(gp(e,d))})}i(IE,"OptionInput");function SW({name:e}){let t=me(n=>n.options_meta[e]?.help);return Dr.default.createElement("div",{className:"help-block small"},t)}i(SW,"OptionHelp");function xW({name:e}){let t=me(n=>n.options_meta[e]?.error);return t?Dr.default.createElement("div",{className:"small text-danger"},t):null}i(xW,"OptionError");function CW({value:e,defaultVal:t}){if(e===t)return null;if(typeof t=="boolean")t=t?"true":"false";else if(Array.isArray(t)){if((0,fg.isEmpty)((0,fg.compact)(e))&&(0,fg.isEmpty)(t))return null;t="[ ]"}else t===""?t='""':t===null&&(t="null");return Dr.default.createElement("div",{className:"small"},"Default: ",Dr.default.createElement("strong",null," ",t," ")," ")}i(CW,"PureOptionDefault");var _W=Wu((e,{name:t})=>({value:e.options[t],defaultVal:e.options_meta[t]?.default}))(CW);function FE(){let e=Be(),t=me(n=>Object.keys(n.options_meta),Mo).sort();return Dr.default.createElement("div",null,Dr.default.createElement("div",{className:"modal-header"},Dr.default.createElement("button",{type:"button",className:"close","data-dismiss":"modal",onClick:()=>e(Xy())},Dr.default.createElement("i",{className:"fa fa-fw fa-times"})),Dr.default.createElement("div",{className:"modal-title"},Dr.default.createElement("h4",null,"Options"))),Dr.default.createElement("div",{className:"modal-body"},Dr.default.createElement("div",{className:"form-horizontal"},t.map(n=>Dr.default.createElement("div",{key:n,className:"form-group"},Dr.default.createElement("div",{className:"col-xs-6"},Dr.default.createElement("label",{htmlFor:n},n),Dr.default.createElement(SW,{name:n})),Dr.default.createElement("div",{className:"col-xs-6"},Dr.default.createElement(IE,{name:n}),Dr.default.createElement(xW,{name:n}),Dr.default.createElement(_W,{name:n})))))),Dr.default.createElement("div",{className:"modal-footer"}))}i(FE,"OptionModal");function EW(){return BE.createElement(DE,null,BE.createElement(FE,null))}i(EW,"OptionModal");var AO=[EW];function zE(){let e=me(n=>n.ui.modal.activeModal),t=AO.find(n=>n.name===e);return e&&t!==void 0?HE.createElement(t,null):HE.createElement("div",null)}i(zE,"PureModal");var UE=class extends Jn.Component{constructor(){super(...arguments);this.state={};this.render=i(()=>{let{showEventLog:n,showCommandBar:s}=this.props;return this.state.error?(console.log("ERR",this.state),Jn.default.createElement("div",{className:"container"},Jn.default.createElement("h1",null,"mitmproxy has crashed."),Jn.default.createElement("pre",null,this.state.error.stack,Jn.default.createElement("br",null),Jn.default.createElement("br",null),"Component Stack:",this.state.errorInfo?.componentStack),Jn.default.createElement("p",null,"Please lodge a bug report at"," ",Jn.default.createElement("a",{href:"https://github.com/mitmproxy/mitmproxy/issues"},"https://github.com/mitmproxy/mitmproxy/issues"),"."))):Jn.default.createElement("div",{id:"container",tabIndex:0},Jn.default.createElement(kE,null),Jn.default.createElement(_E,null),s&&Jn.default.createElement(AE,{key:"commandbar"}),n&&Jn.default.createElement(_O,{key:"eventlog"}),Jn.default.createElement(RE,null),Jn.default.createElement(zE,null))},"render")}static{i(this,"ProxyAppMain")}componentDidMount(){window.addEventListener("keydown",this.props.onKeyDown)}componentWillUnmount(){window.removeEventListener("keydown",this.props.onKeyDown)}componentDidCatch(n,s){this.setState({error:n,errorInfo:s})}},PO=Wu(e=>({showEventLog:e.eventLog.visible,showCommandBar:e.commandBar.visible}),{onKeyDown:XL})(UE);var rc={SEARCH:"s",HIGHLIGHT:"h",SHOW_EVENTLOG:"e",SHOW_COMMANDBAR:"c"};function bW(e){let[t,n]=window.location.hash.substr(1).split("?",2),s=t.substr(1).split("/");if(s[0]==="flows"&&s.length==3){let[l,h]=s.slice(1);e.dispatch(yl(l)),e.dispatch(mf(h))}n&&n.split("&").forEach(l=>{let[h,d]=l.split("=",2),v=decodeURIComponent(d);switch(h){case rc.SEARCH:e.dispatch(Uy(v));break;case rc.HIGHLIGHT:e.dispatch(Wy(v));break;case rc.SHOW_EVENTLOG:e.getState().eventLog.visible||e.dispatch(mp());break;case rc.SHOW_COMMANDBAR:e.getState().commandBar.visible||e.dispatch(f0());break;default:console.error(`unimplemented query arg: ${l}`)}})}i(bW,"updateStoreFromUrl");function TW(e){let t=e.getState(),n={[rc.SEARCH]:t.flows.filter,[rc.HIGHLIGHT]:t.flows.highlight,[rc.SHOW_EVENTLOG]:t.eventLog.visible,[rc.SHOW_COMMANDBAR]:t.commandBar.visible},s=Object.keys(n).filter(d=>n[d]).map(d=>`${d}=${encodeURIComponent(n[d])}`).join("&"),l;t.flows.selected.length>0?l=`/flows/${t.flows.selected[0]}/${t.ui.flow.tab}`:l="/flows",s&&(l+="?"+s);let h=window.location.pathname;h==="blank"&&(h="/"),window.location.hash.substr(1)!==l&&history.replaceState(void 0,"",`${h}#${l}`)}i(TW,"updateUrlFromStore");function WE(e){bW(e),e.subscribe(()=>TW(e))}i(WE,"initialize");var kW="reset",dg=class{static{i(this,"WebsocketBackend")}constructor(t){this.activeFetches={},this.store=t,this.connect()}connect(){this.socket=new WebSocket(location.origin.replace("http","ws")+location.pathname.replace(/\/$/,"")+"/updates"),this.socket.addEventListener("open",()=>this.onOpen()),this.socket.addEventListener("close",t=>this.onClose(t)),this.socket.addEventListener("message",t=>this.onMessage(JSON.parse(t.data))),this.socket.addEventListener("error",t=>this.onError(t))}onOpen(){this.fetchData("state"),this.fetchData("flows"),this.fetchData("events"),this.fetchData("options"),this.store.dispatch(UP())}fetchData(t){let n=[];this.activeFetches[t]=n,xt(`./${t}`).then(s=>s.json()).then(s=>{this.activeFetches[t]===n&&this.receive(t,s)})}onMessage(t){if(t.cmd===kW)return this.fetchData(t.resource);if(t.resource in this.activeFetches)this.activeFetches[t.resource].push(t);else{let n=`${t.resource}_${t.cmd}`.toUpperCase();this.store.dispatch({type:n,...t})}}receive(t,n){let s=`${t}_RECEIVE`.toUpperCase();t==="state"?this.store.dispatch({type:s,payload:n}):this.store.dispatch({type:s,cmd:"receive",resource:t,data:n});let l=this.activeFetches[t];delete this.activeFetches[t],l.forEach(h=>this.onMessage(h)),Object.keys(this.activeFetches).length===0&&this.store.dispatch(WP())}onClose(t){this.store.dispatch($P(`Connection closed at ${new Date().toUTCString()} with error code ${t.code}.`)),console.error("websocket connection closed",t)}onError(...t){console.error("websocket connection errored",t)}};var pg=class{static{i(this,"StaticBackend")}constructor(t){this.store=t,this.onOpen()}onOpen(){this.fetchData("flows"),this.fetchData("options")}fetchData(t){xt(`./${t}`).then(n=>n.json()).then(n=>{this.receive(t,n)})}receive(t,n){let s=`${t}_RECEIVE`.toUpperCase();this.store.dispatch({type:s,cmd:"receive",resource:t,data:n})}};WE(_f);window.MITMWEB_STATIC?window.backend=new pg(_f):window.backend=new dg(_f);window.addEventListener("error",e=>{_f.dispatch(LP(`${e.message} +${e.error.stack}`))});document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("mitmproxy");(0,LO.createRoot)(e).render($E.createElement(EA,{store:_f},$E.createElement(PO,null)))});})(); +/*! Bundled license information: + +react/cjs/react.production.min.js: + (** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +scheduler/cjs/scheduler.production.min.js: + (** + * @license React + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +react-dom/cjs/react-dom.production.min.js: + (** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +use-sync-external-store/cjs/use-sync-external-store-with-selector.production.min.js: + (** + * @license React + * use-sync-external-store-with-selector.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +lodash/lodash.js: + (** + * @license + * Lodash + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + *) + +stable/stable.js: + (*! stable.js 0.1.8, https://github.com/Two-Screen/stable *) + (*! © 2018 Angry Bytes and contributors. MIT licensed. *) + +classnames/index.js: + (*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames + *) */ -/** - * @license - * Lodash - * Copyright OpenJS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -/** @license React v0.20.2 - * scheduler.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v16.13.1 - * react-is.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v17.0.2 - * react-dom.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v17.0.2 - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -//! stable.js 0.1.8, https://github.com/Two-Screen/stable -//! © 2018 Angry Bytes and contributors. MIT licensed. //# sourceMappingURL=app.js.map diff --git a/mitmproxy/tools/web/templates/index.html b/mitmproxy/tools/web/templates/index.html index b7c6a0beef..6e0b60be4c 100644 --- a/mitmproxy/tools/web/templates/index.html +++ b/mitmproxy/tools/web/templates/index.html @@ -1,4 +1,4 @@ - + diff --git a/mitmproxy/tools/web/web_columns.py b/mitmproxy/tools/web/web_columns.py new file mode 100644 index 0000000000..15b9367574 --- /dev/null +++ b/mitmproxy/tools/web/web_columns.py @@ -0,0 +1,15 @@ +# Auto-generated by web/gen/web_columns.py +AVAILABLE_WEB_COLUMNS = [ + "icon", + "index", + "method", + "version", + "path", + "quickactions", + "size", + "status", + "time", + "timestamp", + "tls", + "comment" +] \ No newline at end of file diff --git a/mitmproxy/tools/web/webaddons.py b/mitmproxy/tools/web/webaddons.py index 6d5970988a..7aa209d135 100644 --- a/mitmproxy/tools/web/webaddons.py +++ b/mitmproxy/tools/web/webaddons.py @@ -3,6 +3,7 @@ from collections.abc import Sequence from mitmproxy import ctx +from mitmproxy.tools.web.web_columns import AVAILABLE_WEB_COLUMNS class WebAddon: @@ -15,7 +16,7 @@ def load(self, loader): "web_columns", Sequence[str], ["tls", "icon", "path", "method", "status", "size", "time"], - "Columns to show in the flow list", + f"Columns to show in the flow list. Can be one of the following: {', '.join(AVAILABLE_WEB_COLUMNS)}", ) def running(self): diff --git a/mitmproxy/utils/asyncio_utils.py b/mitmproxy/utils/asyncio_utils.py index 95c01edd00..c545a13d65 100644 --- a/mitmproxy/utils/asyncio_utils.py +++ b/mitmproxy/utils/asyncio_utils.py @@ -1,6 +1,10 @@ import asyncio +import os +import sys import time from collections.abc import Coroutine +from collections.abc import Iterator +from contextlib import contextmanager from mitmproxy.utils import human @@ -27,6 +31,8 @@ def set_task_debug_info( ) -> None: """Set debug info for an externally-spawned task.""" task.created = time.time() # type: ignore + if __debug__ is True and (test := os.environ.get("PYTEST_CURRENT_TEST", None)): + name = f"{name} [created in {test}]" task.set_name(name) if client: task.client = client # type: ignore @@ -55,3 +61,28 @@ def task_repr(task: asyncio.Task) -> str: if client: client = f"{human.format_address(client)}: " return f"{client}{name}{age}" + + +@contextmanager +def install_exception_handler(handler) -> Iterator[None]: + loop = asyncio.get_running_loop() + existing = loop.get_exception_handler() + loop.set_exception_handler(handler) + try: + yield + finally: + loop.set_exception_handler(existing) + + +@contextmanager +def set_eager_task_factory() -> Iterator[None]: + loop = asyncio.get_running_loop() + if sys.version_info < (3, 12): # pragma: no cover + yield + else: + existing = loop.get_task_factory() + loop.set_task_factory(asyncio.eager_task_factory) # type: ignore + try: + yield + finally: + loop.set_task_factory(existing) diff --git a/mitmproxy/utils/signals.py b/mitmproxy/utils/signals.py index f11ee56726..e0a7f419ed 100644 --- a/mitmproxy/utils/signals.py +++ b/mitmproxy/utils/signals.py @@ -7,6 +7,7 @@ - supports type hints - supports async receivers. """ + from __future__ import annotations import asyncio diff --git a/mitmproxy/utils/strutils.py b/mitmproxy/utils/strutils.py index 9b58c2101b..debda43d23 100644 --- a/mitmproxy/utils/strutils.py +++ b/mitmproxy/utils/strutils.py @@ -8,13 +8,11 @@ @overload -def always_bytes(str_or_bytes: None, *encode_args) -> None: - ... +def always_bytes(str_or_bytes: None, *encode_args) -> None: ... @overload -def always_bytes(str_or_bytes: str | bytes, *encode_args) -> bytes: - ... +def always_bytes(str_or_bytes: str | bytes, *encode_args) -> bytes: ... def always_bytes(str_or_bytes: None | str | bytes, *encode_args) -> None | bytes: @@ -29,13 +27,11 @@ def always_bytes(str_or_bytes: None | str | bytes, *encode_args) -> None | bytes @overload -def always_str(str_or_bytes: None, *encode_args) -> None: - ... +def always_str(str_or_bytes: None, *encode_args) -> None: ... @overload -def always_str(str_or_bytes: str | bytes, *encode_args) -> str: - ... +def always_str(str_or_bytes: str | bytes, *encode_args) -> str: ... def always_str(str_or_bytes: None | str | bytes, *decode_args) -> None | str: diff --git a/mitmproxy/utils/vt_codes.py b/mitmproxy/utils/vt_codes.py index 8927a3318b..9bc031bb7b 100644 --- a/mitmproxy/utils/vt_codes.py +++ b/mitmproxy/utils/vt_codes.py @@ -1,6 +1,7 @@ """ This module provides a method to detect if a given file object supports virtual terminal escape codes. """ + import os import sys from typing import IO diff --git a/mitmproxy/version.py b/mitmproxy/version.py index 5e84f10e8e..8b9b3eee3a 100644 --- a/mitmproxy/version.py +++ b/mitmproxy/version.py @@ -2,12 +2,12 @@ import subprocess import sys -VERSION = "11.0.0.dev" +VERSION = "11.0.0" MITMPROXY = "mitmproxy " + VERSION # Serialization format version. This is displayed nowhere, it just needs to be incremented by one # for each change in the file format. -FLOW_FORMAT_VERSION = 20 +FLOW_FORMAT_VERSION = 21 def get_dev_version() -> str: diff --git a/mitmproxy/websocket.py b/mitmproxy/websocket.py index 7424e12696..5558916dca 100644 --- a/mitmproxy/websocket.py +++ b/mitmproxy/websocket.py @@ -5,6 +5,7 @@ This module only defines the classes for individual `WebSocketMessage`s and the `WebSocketData` container. """ + import time import warnings from dataclasses import dataclass @@ -91,6 +92,12 @@ def set_state(self, state: WebSocketMessageState) -> None: ) = state self.type = Opcode(typ) + def _format_ws_message(self) -> bytes: + if self.from_client: + return b"[OUTGOING] " + self.content + else: + return b"[INCOMING] " + self.content + def __repr__(self): if self.type == Opcode.TEXT: return repr(self.content.decode(errors="replace")) @@ -170,3 +177,6 @@ class WebSocketData(serializable.SerializableDataclass): def __repr__(self): return f"" + + def _get_formatted_messages(self) -> bytes: + return b"\n".join(m._format_ws_message() for m in self.messages) diff --git a/pyproject.toml b/pyproject.toml index 19b952e3dd..af30cb0b7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Security", "Topic :: Internet :: WWW/HTTP", @@ -31,50 +32,59 @@ classifiers = [ # https://packaging.python.org/en/latest/discussions/install-requires-vs-requirements/#install-requires # It is not considered best practice to use install_requires to pin dependencies to specific versions. dependencies = [ - "aioquic_mitmproxy>=0.9.21,<0.10", - "asgiref>=3.2.10,<3.8", - "Brotli>=1.0,<1.2", - "certifi>=2019.9.11", # no semver here - this should always be on the last release! - "cryptography>=38.0,<41.1", - "flask>=1.1.1,<3.1", - "h11>=0.11,<0.15", - "h2>=4.1,<5", - "hyperframe>=6.0,<7", - "kaitaistruct>=0.10,<0.11", - "ldap3>=2.8,<2.10", - "mitmproxy_rs>=0.4,<0.5", - "msgpack>=1.0.0, <1.1.0", - "passlib>=1.6.5, <1.8", - "protobuf>=3.14,<5", - "pydivert>=2.0.3,<2.2; sys_platform == 'win32'", - "pyOpenSSL>=22.1,<23.4", - "pyparsing>=2.4.2,<3.2", - "pyperclip>=1.6.0,<1.9", - "ruamel.yaml>=0.16,<0.19", - "sortedcontainers>=2.3,<2.5", - "tornado>=6.2,<7", - "typing-extensions>=4.3,<5; python_version<'3.11'", - "urwid-mitmproxy>=2.1.1,<2.2", - "wsproto>=1.0,<1.3", - "publicsuffix2>=2.20190812,<3", - "zstandard>=0.11,<0.23", + "aioquic>=1.1.0,<=1.2.0", + "asgiref>=3.2.10,<=3.8.1", + "Brotli>=1.0,<=1.1.0", + "certifi>=2019.9.11", # no upper bound here to get latest CA bundle + "cryptography>=42.0,<43.1", # relaxed upper bound here to get security fixes + "flask>=3.0,<=3.0.3", + "h11>=0.11,<=0.14.0", + "h2>=4.1,<=4.1.0", + "hyperframe>=6.0,<=6.0.1", + "kaitaistruct>=0.10,<=0.10", + "ldap3>=2.8,<=2.9.1", + "mitmproxy_rs>=0.9.1,<0.10", # relaxed upper bound here: we control this + "msgpack>=1.0.0,<=1.1.0", + "passlib>=1.6.5,<=1.7.4", + "protobuf>=5.27.2,<=5.28.2", + "pydivert>=2.0.3,<=2.1.0; sys_platform == 'win32'", + "pyOpenSSL>=22.1,<=24.2.1", + "pyparsing>=2.4.2,<=3.1.4", + "pyperclip<=1.9.0,>=1.9.0", + "ruamel.yaml>=0.16,<=0.18.6", + "sortedcontainers>=2.3,<=2.4.0", + "tornado<=6.4.1,>=6.4.1", + "typing-extensions>=4.3,<=4.11.0; python_version<'3.11'", + "urwid>=2.6.14,<=2.6.15", + "wsproto>=1.0,<=1.2.0", + "publicsuffix2>=2.20190812,<=2.20191221", + "zstandard>=0.15,<=0.23.0", ] [project.optional-dependencies] dev = [ - "click>=7.0,<8.2", - "hypothesis>=5.8,<7", - "pdoc>=4.0.0", - "pyinstaller==6.2.0", - "pytest-asyncio>=0.17,<0.22", - "pytest-cov>=2.7.1,<4.2", - "pytest-timeout>=1.3.3,<2.3", - "pytest-xdist>=2.1.0,<3.6", - "pytest>=6.1.0,<8", - "requests>=2.9.1,<3", - "tox>=3.5,<5", - "wheel>=0.36.2,<0.43", - "build>=0.10.0", + "click>=7.0,<=8.1.7", + "hypothesis>=6.104.2,<=6.112.2", + "pdoc>=14.5.1,<=14.7.0", + "pyinstaller==6.10.0", + "pyinstaller-hooks-contrib==2024.8", + "pytest-asyncio>=0.23.6,<=0.24.0", + "pytest-cov>=5.0.0,<=5.0.0", + "pytest-timeout>=2.3.1,<=2.3.1", + "pytest-xdist>=3.5.0,<=3.6.1", + "pytest>=8.2.2,<=8.3.3", + "requests>=2.9.1,<=2.32.3", + "tox>=4.15.1,<=4.21.0", + "wheel>=0.36.2,<=0.44.0", + "build>=0.10.0,<=1.2.2", + "mypy>=1.10.1,<=1.11.2", + "ruff>=0.5.0,<=0.6.8", + "types-certifi>=2021.10.8.3,<=2021.10.8.3", + "types-Flask>=1.1.6,<=1.1.6", + "types-Werkzeug>=1.0.9,<=1.0.9", + "types-requests>=2.32.0.20240622,<=2.32.0.20240914", + "types-cryptography>=3.3.23.2,<=3.3.23.2", + "types-pyOpenSSL>=23.3.0.0,<=24.1.0.20240722", ] [project.urls] @@ -126,10 +136,95 @@ exclude_lines = [ [tool.pytest.ini_options] asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "function" testpaths = "test" addopts = "--capture=no --color=yes" filterwarnings = [ "ignore::DeprecationWarning:tornado.*:", + "ignore:datetime.datetime.utcnow:DeprecationWarning:aioquic.*:", + "error::RuntimeWarning", + "error::pytest.PytestUnraisableExceptionWarning", + # The following warning should only appear on Python 3.11 and below where eager_task_factory is not present + "default:coroutine 'ConnectionHandler.hook_task' was never awaited:RuntimeWarning", +] + +[tool.pytest.individual_coverage] +exclude = [ + "mitmproxy/addons/__init__.py", + "mitmproxy/addons/onboarding.py", + "mitmproxy/addons/onboardingapp/__init__.py", + "mitmproxy/contentviews/__init__.py", + "mitmproxy/contentviews/base.py", + "mitmproxy/contentviews/grpc.py", + "mitmproxy/contrib/*", + "mitmproxy/ctx.py", + "mitmproxy/exceptions.py", + "mitmproxy/flow.py", + "mitmproxy/io/io.py", + "mitmproxy/io/tnetstring.py", + "mitmproxy/log.py", + "mitmproxy/master.py", + "mitmproxy/net/check.py", + "mitmproxy/net/http/cookies.py", + "mitmproxy/net/http/multipart.py", + "mitmproxy/net/tls.py", + "mitmproxy/platform/__init__.py", + "mitmproxy/platform/linux.py", + "mitmproxy/platform/openbsd.py", + "mitmproxy/platform/osx.py", + "mitmproxy/platform/pf.py", + "mitmproxy/platform/windows.py", + "mitmproxy/proxy/__init__.py", + "mitmproxy/proxy/layers/http/__init__.py", + "mitmproxy/proxy/layers/http/_base.py", + "mitmproxy/proxy/layers/http/_events.py", + "mitmproxy/proxy/layers/http/_hooks.py", + "mitmproxy/proxy/layers/http/_http1.py", + "mitmproxy/proxy/layers/http/_http2.py", + "mitmproxy/proxy/layers/http/_http3.py", + "mitmproxy/proxy/layers/http/_http_h2.py", + "mitmproxy/proxy/layers/http/_http_h3.py", + "mitmproxy/proxy/layers/http/_upstream_proxy.py", + "mitmproxy/proxy/layers/tls.py", + "mitmproxy/proxy/server.py", + "mitmproxy/test/taddons.py", + "mitmproxy/test/tflow.py", + "mitmproxy/test/tutils.py", + "mitmproxy/tools/console/commander/commander.py", + "mitmproxy/tools/console/commandexecutor.py", + "mitmproxy/tools/console/commands.py", + "mitmproxy/tools/console/common.py", + "mitmproxy/tools/console/consoleaddons.py", + "mitmproxy/tools/console/eventlog.py", + "mitmproxy/tools/console/flowdetailview.py", + "mitmproxy/tools/console/flowlist.py", + "mitmproxy/tools/console/flowview.py", + "mitmproxy/tools/console/grideditor/base.py", + "mitmproxy/tools/console/grideditor/col_bytes.py", + "mitmproxy/tools/console/grideditor/col_subgrid.py", + "mitmproxy/tools/console/grideditor/col_text.py", + "mitmproxy/tools/console/grideditor/col_viewany.py", + "mitmproxy/tools/console/grideditor/editors.py", + "mitmproxy/tools/console/help.py", + "mitmproxy/tools/console/keybindings.py", + "mitmproxy/tools/console/keymap.py", + "mitmproxy/tools/console/layoutwidget.py", + "mitmproxy/tools/console/master.py", + "mitmproxy/tools/console/options.py", + "mitmproxy/tools/console/overlay.py", + "mitmproxy/tools/console/quickhelp.py", + "mitmproxy/tools/console/searchable.py", + "mitmproxy/tools/console/signals.py", + "mitmproxy/tools/console/statusbar.py", + "mitmproxy/tools/console/tabs.py", + "mitmproxy/tools/console/window.py", + "mitmproxy/tools/main.py", + "mitmproxy/tools/web/app.py", + "mitmproxy/tools/web/master.py", + "mitmproxy/tools/web/webaddons.py", + "mitmproxy/utils/bits.py", + "mitmproxy/utils/pyinstaller/*", + "mitmproxy/utils/vt_codes.py", ] [tool.mypy] @@ -159,19 +254,21 @@ module = "test.*" ignore_errors = true [tool.ruff] -select = ["E", "F", "I"] extend-exclude = ["mitmproxy/contrib/"] + +[tool.ruff.lint] +select = ["E", "F", "I"] ignore = ["F541", "E501"] -[tool.ruff.isort] +[tool.ruff.lint.isort] # these rules are a bit weird, but they mimic our existing reorder_python_imports style. # if we break compatibility here, consider removing all customization + enforce absolute imports. force-single-line = true order-by-type = false section-order = ["future", "standard-library", "third-party", "local-folder","first-party"] no-lines-before = ["first-party"] -known-first-party = ["test", "mitmproxy"] +known-first-party = ["test", "mitmproxy", "mitmproxy_rs"] [tool.tox] legacy_tox_ini = """ @@ -186,17 +283,18 @@ deps = setenv = HOME = {envtmpdir} commands = mitmdump --version - pytest --timeout 60 -vv --cov-report xml \ + pytest --timeout 60 -vv \ + --cov-report xml \ --continue-on-collection-errors \ --cov=mitmproxy --cov=release \ - --full-cov=mitmproxy/ \ {posargs} +[testenv:old-dependencies] +uv_resolution = lowest-direct + [testenv:lint] -deps = - ruff>=0.1.3,<0.2 commands = - ruff . + ruff check . [testenv:filename_matching] deps = @@ -204,16 +302,6 @@ commands = python ./test/filename_matching.py [testenv:mypy] -deps = - mypy==1.6.1 - types-certifi==2021.10.8.3 - types-Flask==1.1.6 - types-Werkzeug==1.0.9 - types-requests==2.31.0.10 - types-cryptography==3.3.23.2 - types-pyOpenSSL==23.3.0.0 - -e .[dev] - commands = mypy {posargs} diff --git a/release/README.md b/release/README.md index 103a204564..96e954b33d 100644 --- a/release/README.md +++ b/release/README.md @@ -1,11 +1,12 @@ # Release Checklist - -1. Make sure that `CHANGELOG.md` is up-to-date with all entries in the "Unreleased" section. -2. Invoke the [release workflow](https://github.com/mitmproxy/mitmproxy/actions/workflows/release.yml) from the GitHub UI. -3. The spawned workflow runs will require manual confirmation on GitHub which you need to approve twice: + +1. Check if `mitmproxy-rs` needs a new release. +2. Make sure that `CHANGELOG.md` is up-to-date with all entries in the "Unreleased" section. +3. Invoke the [release workflow](https://github.com/mitmproxy/mitmproxy/actions/workflows/release.yml) from the GitHub UI. +4. The spawned workflow runs will require manual confirmation on GitHub which you need to approve twice: https://github.com/mitmproxy/mitmproxy/actions -4. Once everything has been deployed, update the website. -5. Verify that the front-page download links for all platforms are working. +5. Once everything has been deployed, update the website. +6. Verify that the front-page download links for all platforms are working. ### GitHub Releases diff --git a/release/build-and-deploy-docker.py b/release/build-and-deploy-docker.py deleted file mode 100644 index 3cf92881dd..0000000000 --- a/release/build-and-deploy-docker.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -""" -Building and deploying docker images is a bit of a special snowflake as we don't get a file we can upload/download -as an artifact. So we need to do everything in one job. -""" -import os -import shutil -import subprocess -from pathlib import Path - -# Security: No third-party dependencies here! - -root = Path(__file__).absolute().parent.parent - -ref = os.environ["GITHUB_REF"] -branch: str | None = None -tag: str | None = None -if ref.startswith("refs/heads/"): - branch = ref.replace("refs/heads/", "") -elif ref.startswith("refs/tags/"): - tag = ref.replace("refs/tags/", "") -else: - raise AssertionError("Failed to parse $GITHUB_REF") - -(whl,) = root.glob("release/dist/mitmproxy-*-py3-none-any.whl") -docker_build_dir = root / "release/docker" -shutil.copy(whl, docker_build_dir / whl.name) - -# Build for this platform and test if it runs. -subprocess.check_call( - [ - "docker", - "buildx", - "build", - "--tag", - "localtesting", - "--load", - "--build-arg", - f"MITMPROXY_WHEEL={whl.name}", - ".", - ], - cwd=docker_build_dir, -) -r = subprocess.run( - [ - "docker", - "run", - "--rm", - "-v", - f"{root / 'release'}:/release", - "localtesting", - "mitmdump", - "-s", - "/release/selftest.py", - ], - capture_output=True, -) -print(r.stdout.decode()) -assert "Self-test successful" in r.stdout.decode() -assert r.returncode == 0 - -# Now we can deploy. -subprocess.check_call( - [ - "docker", - "login", - "-u", - os.environ["DOCKER_USERNAME"], - "-p", - os.environ["DOCKER_PASSWORD"], - ] -) - - -def _buildx(docker_tag): - subprocess.check_call( - [ - "docker", - "buildx", - "build", - "--tag", - docker_tag, - "--push", - "--platform", - "linux/amd64,linux/arm64", - "--build-arg", - f"MITMPROXY_WHEEL={whl.name}", - ".", - ], - cwd=docker_build_dir, - ) - - -if branch == "main": - _buildx("mitmproxy/mitmproxy:dev") -elif branch == "citest": - _buildx("mitmproxy/mitmproxy:citest") -elif tag: - _buildx(f"mitmproxy/mitmproxy:{tag}") - _buildx("mitmproxy/mitmproxy:latest") -else: - raise AssertionError diff --git a/release/build.py b/release/build.py index 9d6bdf6dad..9c2947d224 100755 --- a/release/build.py +++ b/release/build.py @@ -83,23 +83,39 @@ def archive(path: Path) -> tarfile.TarFile | ZipFile2: def version() -> str: - return os.environ.get("GITHUB_REF_NAME", "").replace("/", "-") or os.environ.get( - "BUILD_VERSION", "dev" - ) + if ref := os.environ.get("GITHUB_REF", ""): + if ref.startswith("refs/tags/") and not ref.startswith("refs/tags/v"): + raise AssertionError(f"Unexpected tag: {ref}") + return ( + ref.removeprefix("refs/heads/") + .removeprefix("refs/pull/") + .removeprefix("refs/tags/v") + .replace("/", "-") + ) + else: + return os.environ.get("BUILD_VERSION", "dev") def operating_system() -> str: - match (platform.system(), platform.machine()): - case ("Windows", _): - return "windows" - case ("Linux", _): - return "linux" - case ("Darwin", "x86_64"): - return "macos-x86_64" - case ("Darwin", "arm64"): - return "macos-arm64" - warnings.warn("Unexpected platform.") - return f"{platform.system()}-{platform.machine()}" + match platform.system(): + case "Windows": + system = "windows" + case "Linux": + system = "linux" + case "Darwin": + system = "macos" + case other: + warnings.warn("Unexpected system.") + system = other + match platform.machine(): + case "AMD64" | "x86_64": + machine = "x86_64" + case "arm64": + machine = "arm64" + case other: + warnings.warn("Unexpected platform.") + machine = other + return f"{system}-{machine}" def _pyinstaller(specfile: str) -> None: @@ -288,9 +304,10 @@ def installbuilder_installer(): if not IB_LICENSE.exists(): print("Decrypt InstallBuilder license...") f = cryptography.fernet.Fernet(os.environ["CI_BUILD_KEY"].encode()) - with open(IB_LICENSE.with_suffix(".xml.enc"), "rb") as infile, open( - IB_LICENSE, "wb" - ) as outfile: + with ( + open(IB_LICENSE.with_suffix(".xml.enc"), "rb") as infile, + open(IB_LICENSE, "wb") as outfile, + ): outfile.write(f.decrypt(infile.read())) if not IB_CLI.exists(): @@ -350,6 +367,11 @@ def report(block, blocksize, total): installer = DIST_DIR / f"mitmproxy-{version()}-windows-x64-installer.exe" assert installer.exists() + # unify filenames + installer = installer.rename( + installer.with_name(installer.name.replace("x64", "x86_64")) + ) + print("Run installer...") subprocess.run( [installer, "--mode", "unattended", "--unattendedmodeui", "none"], check=True diff --git a/release/deploy-microsoft-store.py b/release/deploy-microsoft-store.py index ca99e9f002..4df2d6f547 100755 --- a/release/deploy-microsoft-store.py +++ b/release/deploy-microsoft-store.py @@ -9,6 +9,7 @@ - https://docs.microsoft.com/en-us/windows/uwp/monetize/python-code-examples-for-the-windows-store-submission-api - https://docs.microsoft.com/en-us/windows/uwp/monetize/python-code-examples-for-submissions-game-options-and-trailers """ + import http.client import json import os diff --git a/release/deploy.py b/release/deploy.py index 9e652a1480..f9dee28c82 100755 --- a/release/deploy.py +++ b/release/deploy.py @@ -14,7 +14,9 @@ if ref.startswith("refs/heads/"): branch = ref.replace("refs/heads/", "") elif ref.startswith("refs/tags/"): - tag = ref.replace("refs/tags/", "") + if not ref.startswith("refs/tags/v"): + raise AssertionError(f"Unexpected tag: {ref}") + tag = ref.replace("refs/tags/v", "") else: raise AssertionError diff --git a/release/docker/Dockerfile b/release/docker/Dockerfile index f0255c8cf4..7ed4350d86 100644 --- a/release/docker/Dockerfile +++ b/release/docker/Dockerfile @@ -1,8 +1,7 @@ -FROM python:3.11-bullseye as wheelbuilder +FROM python:3.11-bullseye AS wheelbuilder -ARG MITMPROXY_WHEEL -COPY $MITMPROXY_WHEEL /wheels/ -RUN pip install wheel && pip wheel --wheel-dir /wheels /wheels/${MITMPROXY_WHEEL} +COPY mitmproxy-*-py3-none-any.whl /wheels/ +RUN pip install wheel && pip wheel --wheel-dir /wheels /wheels/*.whl FROM python:3.11-slim-bullseye @@ -11,6 +10,9 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends gosu nano \ && rm -rf /var/lib/apt/lists/* +RUN mkdir /home/mitmproxy/.mitmproxy \ + && chown mitmproxy:mitmproxy /home/mitmproxy/.mitmproxy + COPY --from=wheelbuilder /wheels /wheels RUN pip install --no-index --find-links=/wheels mitmproxy RUN rm -rf /wheels diff --git a/release/docker/README.md b/release/docker/README.md index d84382557d..b5744e4532 100644 --- a/release/docker/README.md +++ b/release/docker/README.md @@ -2,5 +2,4 @@ 1. Copy `mitmproxy-$VERSION-py3-none-any.whl` into this directory. You can get the latest public release at https://mitmproxy.org/downloads/. - 2. Replace $VERSION with your mitmproxy version and - run `docker build --build-arg MITMPROXY_WHEEL=mitmproxy-$VERSION-py3-none-any.whl .`. + 2. Run `docker build .`. diff --git a/release/release.py b/release/release.py index f8ddbb8253..8ac18d9369 100755 --- a/release/release.py +++ b/release/release.py @@ -72,7 +72,7 @@ def get_json(url: str) -> dict: title = f"## {date}: mitmproxy {version}" cl = changelog.read_text("utf8") assert title not in cl - cl, ok = re.subn(r"(?<=## Unreleased: mitmproxy next)", f"\n\n\n\n{title}", cl) + cl, ok = re.subn(r"(?<=## Unreleased: mitmproxy next)", f"\n\n\n{title}", cl) assert ok == 1 changelog.write_text(cl, "utf8") @@ -99,7 +99,8 @@ def get_json(url: str) -> dict: subprocess.run( ["git", "commit", "-a", "-m", f"mitmproxy {version}"], cwd=root, check=True ) - subprocess.run(["git", "tag", version], cwd=root, check=True) + tag_name = f"v{version}" + subprocess.run(["git", "tag", tag_name], cwd=root, check=True) release_sha = subprocess.run( ["git", "rev-parse", "HEAD"], cwd=root, @@ -124,7 +125,7 @@ def get_json(url: str) -> dict: print("➡️ Pushing...") subprocess.run( - ["git", "push", "--atomic", "origin", branch, version], cwd=root, check=True + ["git", "push", "--atomic", "origin", branch, tag_name], cwd=root, check=True ) print("➡️ Creating release on GitHub...") @@ -133,7 +134,7 @@ def get_json(url: str) -> dict: "gh", "release", "create", - version, + tag_name, "--title", f"mitmproxy {version}", "--notes-file", @@ -145,7 +146,7 @@ def get_json(url: str) -> dict: print("➡️ Dispatching release workflow...") subprocess.run( - ["gh", "workflow", "run", "main.yml", "--ref", version], cwd=root, check=True + ["gh", "workflow", "run", "main.yml", "--ref", tag_name], cwd=root, check=True ) print("") @@ -175,7 +176,7 @@ def get_json(url: str) -> dict: time.sleep(30) # relatively strict rate limits here. print("➡️ Checking GitHub Releases...") - resp = get(f"https://api.github.com/repos/{repo}/releases/tags/{version}") + resp = get(f"https://api.github.com/repos/{repo}/releases/tags/{tag_name}") assert resp.status == 200 print("➡️ Checking PyPI...") diff --git a/release/selftest.py b/release/selftest.py index b601772f18..4ad7acb4f3 100644 --- a/release/selftest.py +++ b/release/selftest.py @@ -3,6 +3,7 @@ mitmdump -s selftest.py -p 0 """ + import asyncio import logging import ssl @@ -29,6 +30,8 @@ def running(): async def make_request(): try: cafile = Path(ctx.options.confdir).expanduser() / "mitmproxy-ca.pem" + while not cafile.exists(): + await asyncio.sleep(0.01) ssl_ctx = ssl.create_default_context(cafile=cafile) port = ctx.master.addons.get("proxyserver").listen_addrs()[0][1] reader, writer = await asyncio.open_connection("127.0.0.1", port, ssl=ssl_ctx) diff --git a/release/specs/standalone.spec b/release/specs/standalone.spec index 768b2ade0d..bcc0f3b9c4 100644 --- a/release/specs/standalone.spec +++ b/release/specs/standalone.spec @@ -7,6 +7,11 @@ for tool in ["mitmproxy", "mitmdump", "mitmweb"]: if tool != "mitmproxy": excludes.append("mitmproxy.tools.console") + options = [] + if tool == "mitmdump": + # https://github.com/mitmproxy/mitmproxy/issues/6757 + options.append(("unbuffered", None, "OPTION")) + a = Analysis( [tool], excludes=excludes, @@ -19,8 +24,8 @@ for tool in ["mitmproxy", "mitmdump", "mitmweb"]: a.binaries, a.zipfiles, a.datas, - [], + options, name=tool, console=True, - icon='icon.ico', + icon="icon.ico", ) diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8cd2a7ab80..0000000000 --- a/setup.cfg +++ /dev/null @@ -1,31 +0,0 @@ -[tool:full_coverage] -exclude = - mitmproxy/tools/ - release/hooks - -[tool:individual_coverage] -exclude = - mitmproxy/addons/onboarding.py - mitmproxy/connections.py - mitmproxy/contentviews/base.py - mitmproxy/contentviews/grpc.py - mitmproxy/ctx.py - mitmproxy/exceptions.py - mitmproxy/flow.py - mitmproxy/io/io.py - mitmproxy/io/tnetstring.py - mitmproxy/log.py - mitmproxy/master.py - mitmproxy/net/check.py - mitmproxy/net/http/cookies.py - mitmproxy/net/http/message.py - mitmproxy/net/http/multipart.py - mitmproxy/net/tls.py - mitmproxy/net/udp_wireguard.py - mitmproxy/options.py - mitmproxy/proxy/config.py - mitmproxy/proxy/server.py - mitmproxy/proxy/layers/tls.py - mitmproxy/utils/bits.py - mitmproxy/utils/vt_codes.py - mitmproxy/utils/pyinstaller diff --git a/test/bench/benchmark.py b/test/bench/benchmark.py index b0d6902744..f570704843 100644 --- a/test/bench/benchmark.py +++ b/test/bench/benchmark.py @@ -46,7 +46,7 @@ def load(self, loader): "benchmark_save_path", str, "/tmp/profile", - "Destination for the .prof and and .bench result files", + "Destination for the .prof and .bench result files", ) ctx.options.update( mode="reverse:http://devd.io:10001", diff --git a/test/conftest.py b/test/conftest.py index 63d2164110..c830a5f7c5 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -3,13 +3,12 @@ import asyncio import os import socket +import sys import pytest from mitmproxy.utils import data -pytest_plugins = ("test.full_coverage_plugin",) - skip_windows = pytest.mark.skipif(os.name == "nt", reason="Skipping due to Windows") skip_not_windows = pytest.mark.skipif( @@ -28,6 +27,19 @@ skip_no_ipv6 = pytest.mark.skipif(no_ipv6, reason="Host has no IPv6 support") +class EagerTaskCreationEventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def new_event_loop(self): + loop = super().new_event_loop() + if sys.version_info >= (3, 12): + loop.set_task_factory(asyncio.eager_task_factory) + return loop + + +@pytest.fixture(scope="session") +def event_loop_policy(request): + return EagerTaskCreationEventLoopPolicy() + + @pytest.fixture() def tdata(): return data.Data(__name__) diff --git a/test/full_coverage_plugin.py b/test/full_coverage_plugin.py deleted file mode 100644 index 36ac7f263d..0000000000 --- a/test/full_coverage_plugin.py +++ /dev/null @@ -1,144 +0,0 @@ -import configparser -import os -import sys - -import pytest - -here = os.path.abspath(os.path.dirname(__file__)) - - -enable_coverage = False -coverage_values = [] -coverage_passed = True -no_full_cov = [] - - -def pytest_addoption(parser): - parser.addoption( - "--full-cov", - action="append", - dest="full_cov", - default=[], - help="Require full test coverage of 100%% for this module/path/filename (multi-allowed). Default: none", - ) - - parser.addoption( - "--no-full-cov", - action="append", - dest="no_full_cov", - default=[], - help="Exclude file from a parent 100%% coverage requirement (multi-allowed). Default: none", - ) - - -def pytest_configure(config): - global enable_coverage - global no_full_cov - - enable_coverage = ( - config.getoption("file_or_dir") - and len(config.getoption("file_or_dir")) == 0 - and config.getoption("full_cov") - and len(config.getoption("full_cov")) > 0 - and config.pluginmanager.getplugin("_cov") is not None - and config.pluginmanager.getplugin("_cov").cov_controller is not None - and config.pluginmanager.getplugin("_cov").cov_controller.cov is not None - ) - - c = configparser.ConfigParser() - c.read(os.path.join(here, "..", "setup.cfg")) - fs = c["tool:full_coverage"]["exclude"].split("\n") - no_full_cov = config.option.no_full_cov + [f.strip() for f in fs] - - -@pytest.hookimpl(hookwrapper=True) -def pytest_runtestloop(session): - global enable_coverage - global coverage_values - global coverage_passed - global no_full_cov - - if not enable_coverage: - yield - return - - cov = session.config.pluginmanager.getplugin("_cov").cov_controller.cov - - if os.name == "nt": - cov.exclude("pragma: windows no cover") - - if sys.platform == "darwin": - cov.exclude("pragma: osx no cover") - - if os.environ.get("OPENSSL") == "old": - cov.exclude("pragma: openssl-old no cover") - - yield - - coverage_values = {name: 0 for name in session.config.option.full_cov} - - prefix = os.getcwd() - - excluded_files = [os.path.normpath(f) for f in no_full_cov] - measured_files = [ - os.path.normpath(os.path.relpath(f, prefix)) - for f in cov.get_data().measured_files() - ] - measured_files = [ - f - for f in measured_files - if not any(f.startswith(excluded_f) for excluded_f in excluded_files) - ] - - for name in coverage_values.keys(): - files = [f for f in measured_files if f.startswith(os.path.normpath(name))] - try: - with open(os.devnull, "w") as null: - overall = cov.report(files, ignore_errors=True, file=null) - singles = [ - (s, cov.report(s, ignore_errors=True, file=null)) for s in files - ] - coverage_values[name] = (overall, singles) - except Exception: - pass - - if any(v < 100 for v, _ in coverage_values.values()): - # make sure we get the EXIT_TESTSFAILED exit code - session.testsfailed += 1 - coverage_passed = False - - -def pytest_terminal_summary(terminalreporter, exitstatus, config): - global enable_coverage - global coverage_values - global coverage_passed - global no_full_cov - - if not enable_coverage: - return - - terminalreporter.write("\n") - if not coverage_passed: - markup = {"red": True, "bold": True} - msg = "FAIL: Full test coverage not reached!\n" - terminalreporter.write(msg, **markup) - - for name in sorted(coverage_values.keys()): - msg = f"Coverage for {name}: {coverage_values[name][0]:.2f}%\n" - if coverage_values[name][0] < 100: - markup = {"red": True, "bold": True} - for s, v in sorted(coverage_values[name][1]): - if v < 100: - msg += f" {s}: {v:.2f}%\n" - else: - markup = {"green": True} - terminalreporter.write(msg, **markup) - else: - msg = "SUCCESS: Full test coverage reached in modules and files:\n" - msg += "{}\n\n".format("\n".join(config.option.full_cov)) - terminalreporter.write(msg, green=True) - - msg = "\nExcluded files:\n" - for s in sorted(no_full_cov): - msg += f" {s}\n" - terminalreporter.write(msg) diff --git a/test/helper_tools/loggrep.py b/test/helper_tools/loggrep.py index c9528f4913..965f70fb6a 100755 --- a/test/helper_tools/loggrep.py +++ b/test/helper_tools/loggrep.py @@ -11,7 +11,7 @@ port = sys.argv[1] matches = False for line in fileinput.input(sys.argv[2:]): - if re.match(r"^\[|(\d+\.){3}", line): + if re.search(r"^\[|(\d+\.){3}", line): matches = port in line if matches: print(line, end="") diff --git a/test/individual_coverage.py b/test/individual_coverage.py index 72ba8e1048..1d6648ca6e 100755 --- a/test/individual_coverage.py +++ b/test/individual_coverage.py @@ -1,108 +1,119 @@ #!/usr/bin/env python3 -import configparser -import contextlib -import glob -import io -import itertools -import multiprocessing +import ast +import asyncio +import fnmatch import os +import re +import subprocess import sys +from pathlib import Path -import pytest +import tomllib +root = Path(__file__).parent.parent.absolute() -def run_tests(src, test, fail): - stderr = io.StringIO() - stdout = io.StringIO() - with contextlib.redirect_stderr(stderr): - with contextlib.redirect_stdout(stdout): - e = pytest.main( - [ + +async def main(): + with open("pyproject.toml", "rb") as f: + data = tomllib.load(f) + + exclude = re.compile( + "|".join( + f"({fnmatch.translate(x)})" + for x in data["tool"]["pytest"]["individual_coverage"]["exclude"] + ) + ) + + sem = asyncio.Semaphore(os.cpu_count() or 1) + + async def run_tests(f: Path, should_fail: bool) -> None: + if f.name == "__init__.py": + mod = ast.parse(f.read_text()) + full_cov_on_import = all( + isinstance(stmt, (ast.ImportFrom, ast.Import, ast.Assign)) + for stmt in mod.body + ) + if full_cov_on_import: + if should_fail: + raise RuntimeError( + f"Remove {f} from tool.pytest.individual_coverage in pyproject.toml." + ) + else: + print(f"{f}: skip __init__.py file without logic") + return + + test_file = Path("test") / f.parent.with_name(f"test_{f.parent.name}.py") + else: + test_file = Path("test") / f.with_name(f"test_{f.name}") + + coverage_file = f".coverage-{str(f).replace('/','-')}" + + async with sem: + try: + proc = await asyncio.create_subprocess_exec( + "pytest", "-qq", "--disable-pytest-warnings", "--cov", - src.replace(".py", "").replace("/", "."), + str(f.with_suffix("")).replace("/", "."), "--cov-fail-under", "100", "--cov-report", "term-missing:skip-covered", - "-o", - "faulthandler_timeout=0", - test, - ] - ) + test_file, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env={ + "COVERAGE_FILE": coverage_file, + **os.environ, + }, + ) + stdout, stderr = await asyncio.wait_for(proc.communicate(), 60) + except TimeoutError: + raise RuntimeError(f"{f}: timeout") + finally: + Path(coverage_file).unlink(missing_ok=True) - if e == 0: - if fail: - print( - "FAIL DUE TO UNEXPECTED SUCCESS:", - src, - "Please remove this file from setup.cfg tool:individual_coverage/exclude.", - ) - e = 42 - else: - print(".") - else: - if fail: - print("Ignoring allowed fail:", src) - e = 0 - else: - cov = [ - line - for line in stdout.getvalue().split("\n") - if (src in line) or ("was never imported" in line) - ] - if len(cov) == 1: - print("FAIL:", cov[0]) + if should_fail: + if proc.returncode != 0: + print(f"{f}: excluded") + else: + raise RuntimeError( + f"{f} is now fully covered by {test_file}. Remove it from tool.pytest.individual_coverage in pyproject.toml." + ) else: - print("FAIL:", src, test, stdout.getvalue(), stdout.getvalue()) - print(stderr.getvalue()) - print(stdout.getvalue()) - - sys.exit(e) - - -def start_pytest(src, test, fail): - # run pytest in a new process, otherwise imports and modules might conflict - proc = multiprocessing.Process(target=run_tests, args=(src, test, fail)) - proc.start() - proc.join() - return (src, test, proc.exitcode) - - -def main(): - c = configparser.ConfigParser() - c.read("setup.cfg") - fs = c["tool:individual_coverage"]["exclude"].strip().split("\n") - no_individual_cov = [f.strip() for f in fs] - - excluded = [ - "mitmproxy/contrib/", - "mitmproxy/test/", - "mitmproxy/tools/", - "mitmproxy/platform/", - ] - src_files = glob.glob("mitmproxy/**/*.py", recursive=True) - src_files = [f for f in src_files if os.path.basename(f) != "__init__.py"] - src_files = [ - f for f in src_files if not any(os.path.normpath(p) in f for p in excluded) - ] - if len(sys.argv) > 1: - src_files = [f for f in src_files if sys.argv[1] in str(f)] - - ps = [] - for src in sorted(src_files): - test = os.path.join( - "test", os.path.dirname(src), "test_" + os.path.basename(src) + if proc.returncode == 0: + print(f"{f}: ok") + else: + raise RuntimeError( + f"{f} is not fully covered by {test_file}:\n{stdout.decode(errors='ignore')}\n{stderr.decode(errors='ignore')}" + ) + + tasks = [] + for f in (root / "mitmproxy").glob("**/*.py"): + f = f.relative_to(root) + + if len(sys.argv) > 1 and sys.argv[1] not in str(f): + continue + + if f.name == "__init__.py" and f.stat().st_size == 0: + print(f"{f}: empty") + continue + + tasks.append( + asyncio.create_task(run_tests(f, should_fail=exclude.match(str(f)))) ) - if os.path.isfile(test): - ps.append((src, test, src in no_individual_cov)) - result = list(itertools.starmap(start_pytest, ps)) + exit_code = 0 + for task in asyncio.as_completed(tasks): + try: + await task + except RuntimeError as e: + print(e) + exit_code = 1 - if any(e != 0 for _, _, e in result): - sys.exit(1) + sys.exit(exit_code) if __name__ == "__main__": - main() + asyncio.run(main()) diff --git a/test/mitmproxy/addons/test_asgiapp.py b/test/mitmproxy/addons/test_asgiapp.py index 0926f091e1..fd331cdd72 100644 --- a/test/mitmproxy/addons/test_asgiapp.py +++ b/test/mitmproxy/addons/test_asgiapp.py @@ -14,7 +14,6 @@ @tapp.route("/") def hello(): - print("CALLED") return "testapp" @@ -57,57 +56,70 @@ async def test_asgi_full(caplog): assert await ps.setup_servers() proxy_addr = ("127.0.0.1", ps.listen_addrs()[0][1]) - reader, writer = await asyncio.open_connection(*proxy_addr) + # We parallelize connection establishment/closure because those operations tend to be slow. + [ + (r1, w1), + (r2, w2), + (r3, w3), + (r4, w4), + (r5, w5), + ] = await asyncio.gather( + asyncio.open_connection(*proxy_addr), + asyncio.open_connection(*proxy_addr), + asyncio.open_connection(*proxy_addr), + asyncio.open_connection(*proxy_addr), + asyncio.open_connection(*proxy_addr), + ) + req = f"GET http://testapp:80/ HTTP/1.1\r\n\r\n" - writer.write(req.encode()) - header = await reader.readuntil(b"\r\n\r\n") + w1.write(req.encode()) + header = await r1.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 200 OK") - body = await reader.readuntil(b"testapp") + body = await r1.readuntil(b"testapp") assert body == b"testapp" - writer.close() - await writer.wait_closed() - reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://testapp:80/parameters?param1=1¶m2=2 HTTP/1.1\r\n\r\n" - writer.write(req.encode()) - header = await reader.readuntil(b"\r\n\r\n") + w2.write(req.encode()) + header = await r2.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 200 OK") - body = await reader.readuntil(b"}") + body = await r2.readuntil(b"}") assert body == b'{"param1": "1", "param2": "2"}' - writer.close() - await writer.wait_closed() - reader, writer = await asyncio.open_connection(*proxy_addr) req = f"POST http://testapp:80/requestbody HTTP/1.1\r\nContent-Length: 6\r\n\r\nHello!" - writer.write(req.encode()) - header = await reader.readuntil(b"\r\n\r\n") + w3.write(req.encode()) + header = await r3.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 200 OK") - body = await reader.readuntil(b"}") + body = await r3.readuntil(b"}") assert body == b'{"body": "Hello!"}' - writer.close() - await writer.wait_closed() - reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://errapp:80/?foo=bar HTTP/1.1\r\n\r\n" - writer.write(req.encode()) - header = await reader.readuntil(b"\r\n\r\n") + w4.write(req.encode()) + header = await r4.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 500") - body = await reader.readuntil(b"ASGI Error") + body = await r4.readuntil(b"ASGI Error") assert body == b"ASGI Error" - writer.close() - await writer.wait_closed() assert "ValueError" in caplog.text - reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://noresponseapp:80/ HTTP/1.1\r\n\r\n" - writer.write(req.encode()) - header = await reader.readuntil(b"\r\n\r\n") + w5.write(req.encode()) + header = await r5.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 500") - body = await reader.readuntil(b"ASGI Error") + body = await r5.readuntil(b"ASGI Error") assert body == b"ASGI Error" - writer.close() - await writer.wait_closed() assert "no response sent" in caplog.text + w1.close() + w2.close() + w3.close() + w4.close() + w5.close() + await asyncio.gather( + w1.wait_closed(), + w2.wait_closed(), + w3.wait_closed(), + w4.wait_closed(), + w5.wait_closed(), + ) + tctx.configure(ps, server=False) assert await ps.setup_servers() diff --git a/test/mitmproxy/addons/test_block.py b/test/mitmproxy/addons/test_block.py index 3fad8f5b8c..afcd508492 100644 --- a/test/mitmproxy/addons/test_block.py +++ b/test/mitmproxy/addons/test_block.py @@ -2,6 +2,7 @@ from mitmproxy import connection from mitmproxy.addons import block +from mitmproxy.proxy.mode_specs import ProxyMode from mitmproxy.test import taddons @@ -59,3 +60,17 @@ async def test_block_global(block_global, block_private, should_be_killed, addre client = connection.Client(peername=address, sockname=("127.0.0.1", 8080)) ar.client_connected(client) assert bool(client.error) == should_be_killed + + +async def test_ignore_local_mode(): + """At least on macOS, local mode peername may be the client's public IP.""" + ar = block.Block() + with taddons.context(ar) as tctx: + tctx.configure(ar, block_private=True) + client = connection.Client( + peername=("192.168.1.1", 0), + sockname=("127.0.0.1", 8080), + proxy_mode=ProxyMode.parse("local"), + ) + ar.client_connected(client) + assert not client.error diff --git a/test/mitmproxy/addons/test_blocklist.py b/test/mitmproxy/addons/test_blocklist.py index 9187443b28..b7c7e536d3 100644 --- a/test/mitmproxy/addons/test_blocklist.py +++ b/test/mitmproxy/addons/test_blocklist.py @@ -22,20 +22,21 @@ def test_parse_spec_err(filter, err): class TestBlockList: @pytest.mark.parametrize( - "filter,status_code", + "filter,request_url,status_code", [ - (":~u example.org:404", 404), - (":~u example.com:404", None), - ("/!jpg/418", None), - ("/!png/418", 418), + (":~u example.org:404", b"https://example.org/images/test.jpg", 404), + (":~u example.com:404", b"https://example.org/images/test.jpg", None), + (":~u test:404", b"https://example.org/images/TEST.jpg", 404), + ("/!jpg/418", b"https://example.org/images/test.jpg", None), + ("/!png/418", b"https://example.org/images/test.jpg", 418), ], ) - def test_block(self, filter, status_code): + def test_block(self, filter, request_url, status_code): bl = blocklist.BlockList() with taddons.context(bl) as tctx: tctx.configure(bl, block_list=[filter]) f = tflow.tflow() - f.request.url = b"https://example.org/images/test.jpg" + f.request.url = request_url bl.request(f) if status_code is not None: assert f.response.status_code == status_code diff --git a/test/mitmproxy/addons/test_browser.py b/test/mitmproxy/addons/test_browser.py index e5b9c15570..ba9ed43631 100644 --- a/test/mitmproxy/addons/test_browser.py +++ b/test/mitmproxy/addons/test_browser.py @@ -6,9 +6,11 @@ def test_browser(caplog): caplog.set_level("INFO") - with mock.patch("subprocess.Popen") as po, mock.patch( - "shutil.which" - ) as which, taddons.context(): + with ( + mock.patch("subprocess.Popen") as po, + mock.patch("shutil.which") as which, + taddons.context(), + ): which.return_value = "chrome" b = browser.Browser() b.start() @@ -48,9 +50,10 @@ def subprocess_run_mock(cmd, **kwargs): returncode = 0 if cmd == ["flatpak", "info", "com.google.Chrome"] else 1 return mock.Mock(returncode=returncode) - with mock.patch("shutil.which") as which, mock.patch( - "subprocess.run" - ) as subprocess_run: + with ( + mock.patch("shutil.which") as which, + mock.patch("subprocess.run") as subprocess_run, + ): which.side_effect = lambda cmd: cmd == "flatpak" subprocess_run.side_effect = subprocess_run_mock assert browser.get_browser_cmd() == [ @@ -62,9 +65,10 @@ def subprocess_run_mock(cmd, **kwargs): async def test_get_browser_cmd_no_flatpak(): - with mock.patch("shutil.which") as which, mock.patch( - "subprocess.run" - ) as subprocess_run: + with ( + mock.patch("shutil.which") as which, + mock.patch("subprocess.run") as subprocess_run, + ): which.side_effect = lambda cmd: cmd == "flatpak" subprocess_run.return_value = mock.Mock(returncode=1) assert browser.get_browser_cmd() is None diff --git a/test/mitmproxy/addons/test_clientplayback.py b/test/mitmproxy/addons/test_clientplayback.py index f9f889e42f..b2f210606f 100644 --- a/test/mitmproxy/addons/test_clientplayback.py +++ b/test/mitmproxy/addons/test_clientplayback.py @@ -17,23 +17,48 @@ @asynccontextmanager async def tcp_server(handle_conn, **server_args) -> Address: - server = await asyncio.start_server(handle_conn, "127.0.0.1", 0, **server_args) + """TCP server context manager that... + + 1. Exits only after all handlers have returned. + 2. Ensures that all handlers are closed properly. If we don't do that, + we get ghost errors in others tests from StreamWriter.__del__. + + Spawning a TCP server is relatively slow. Consider using in-memory networking for faster tests. + """ + if not hasattr(asyncio, "TaskGroup"): + pytest.skip("Skipped because asyncio.TaskGroup is unavailable.") + + tasks = asyncio.TaskGroup() + + async def handle_conn_wrapper( + reader: asyncio.StreamReader, + writer: asyncio.StreamWriter, + ) -> None: + try: + await handle_conn(reader, writer) + except Exception as e: + print(f"!!! TCP handler failed: {e}") + raise + finally: + if not writer.is_closing(): + writer.close() + await writer.wait_closed() + + async def _handle(r, w): + tasks.create_task(handle_conn_wrapper(r, w)) + + server = await asyncio.start_server(_handle, "127.0.0.1", 0, **server_args) await server.start_serving() - try: - yield server.sockets[0].getsockname() - finally: - server.close() + async with server: + async with tasks: + yield server.sockets[0].getsockname() @pytest.mark.parametrize("mode", ["http", "https", "upstream", "err"]) @pytest.mark.parametrize("concurrency", [-1, 1]) async def test_playback(tdata, mode, concurrency): - handler_ok = asyncio.Event() - async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): if mode == "err": - writer.close() - handler_ok.set() return req = await reader.readline() if mode == "upstream": @@ -49,7 +74,6 @@ async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): writer.write(b"HTTP/1.1 204 No Content\r\n\r\n") await writer.drain() assert not await reader.read() - handler_ok.set() cp = ClientPlayback() ps = Proxyserver() @@ -92,22 +116,20 @@ async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): cp.start_replay([flow]) assert cp.count() == 1 await asyncio.wait_for(cp.queue.join(), 5) - await asyncio.wait_for(handler_ok.wait(), 5) - cp.done() - if mode != "err": - assert flow.response.status_code == 204 + while cp.replay_tasks: + await asyncio.sleep(0.001) + if mode != "err": + assert flow.response.status_code == 204 + await cp.done() async def test_playback_https_upstream(): - handler_ok = asyncio.Event() - async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): conn_req = await reader.readuntil(b"\r\n\r\n") - assert conn_req == b"CONNECT address:22 HTTP/1.1\r\n\r\n" + assert conn_req == b"CONNECT address:22 HTTP/1.1\r\nHost: address:22\r\n\r\n" writer.write(b"HTTP/1.1 502 Bad Gateway\r\n\r\n") await writer.drain() assert not await reader.read() - handler_ok.set() cp = ClientPlayback() ps = Proxyserver() @@ -122,17 +144,17 @@ async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): cp.start_replay([flow]) assert cp.count() == 1 await asyncio.wait_for(cp.queue.join(), 5) - await asyncio.wait_for(handler_ok.wait(), 5) - cp.done() - assert flow.response is None - assert ( - str(flow.error) - == f"Upstream proxy {addr[0]}:{addr[1]} refused HTTP CONNECT request: 502 Bad Gateway" - ) + + assert flow.response is None + assert ( + str(flow.error) + == f"Upstream proxy {addr[0]}:{addr[1]} refused HTTP CONNECT request: 502 Bad Gateway" + ) + await cp.done() async def test_playback_crash(monkeypatch, caplog_async): - async def raise_err(): + async def raise_err(*_, **__): raise ValueError("oops") monkeypatch.setattr(ReplayHandler, "replay", raise_err) @@ -141,8 +163,9 @@ async def raise_err(): cp.running() cp.start_replay([tflow.tflow(live=False)]) await caplog_async.await_log("Client replay has crashed!") + assert "oops" in caplog_async.caplog.text assert cp.count() == 0 - cp.done() + await cp.done() def test_check(): diff --git a/test/mitmproxy/addons/test_cut.py b/test/mitmproxy/addons/test_cut.py index d2a30abb45..146bde170c 100644 --- a/test/mitmproxy/addons/test_cut.py +++ b/test/mitmproxy/addons/test_cut.py @@ -58,9 +58,21 @@ def test_extract(tdata): assert "CERTIFICATE" in cut.extract("server_conn.certificate_list", tf) +def test_extract_websocket(): + tf = tflow.twebsocketflow(messages=True) + extracted_request_content = cut.extract("request.content", tf) + extracted_response_content = cut.extract("response.content", tf) + assert b"hello binary" in extracted_request_content + assert b"hello text" in extracted_request_content + assert b"it's me" in extracted_request_content + assert b"hello binary" in extracted_response_content + assert b"hello text" in extracted_response_content + assert b"it's me" in extracted_response_content + + def test_extract_str(): tf = tflow.tflow() - tf.request.raw_content = b"\xFF" + tf.request.raw_content = b"\xff" assert cut.extract_str("request.raw_content", tf) == r"b'\xff'" diff --git a/test/mitmproxy/addons/test_dns_resolver.py b/test/mitmproxy/addons/test_dns_resolver.py index a72d5ed257..11e97ed8ab 100644 --- a/test/mitmproxy/addons/test_dns_resolver.py +++ b/test/mitmproxy/addons/test_dns_resolver.py @@ -1,138 +1,154 @@ import asyncio -import ipaddress import socket -from collections.abc import Callable +import sys +import typing import pytest +import mitmproxy_rs from mitmproxy import dns from mitmproxy.addons import dns_resolver from mitmproxy.addons import proxyserver -from mitmproxy.connection import Address from mitmproxy.proxy.mode_specs import ProxyMode from mitmproxy.test import taddons from mitmproxy.test import tflow from mitmproxy.test import tutils -async def test_simple(monkeypatch): - monkeypatch.setattr( - dns_resolver, "resolve_message", lambda _, __: asyncio.sleep(0, "resp") - ) - +async def test_ignores_reverse_mode(): dr = dns_resolver.DnsResolver() with taddons.context(dr, proxyserver.Proxyserver()): f = tflow.tdnsflow() - await dr.dns_request(f) - assert f.response + f.client_conn.proxy_mode = ProxyMode.parse("dns") + assert dr._should_resolve(f) + + f.client_conn.proxy_mode = ProxyMode.parse("wireguard") + f.server_conn.address = ("10.0.0.53", 53) + assert dr._should_resolve(f) - f = tflow.tdnsflow() f.client_conn.proxy_mode = ProxyMode.parse("reverse:dns://8.8.8.8") - await dr.dns_request(f) - assert not f.response - - -class DummyLoop: - async def getnameinfo(self, socketaddr: Address, flags: int = 0): - assert flags == socket.NI_NAMEREQD - if socketaddr[0] in ("8.8.8.8", "2001:4860:4860::8888"): - return ("dns.google", "") - e = socket.gaierror() - e.errno = socket.EAI_NONAME - raise e - - async def getaddrinfo(self, host: str, port: int, *, family: int): - e = socket.gaierror() - e.errno = socket.EAI_NONAME - if family == socket.AF_INET: - if host == "dns.google": - return [(socket.AF_INET, None, None, None, ("8.8.8.8", port))] - elif family == socket.AF_INET6: - if host == "dns.google": - return [ - ( - socket.AF_INET6, - None, - None, - None, - ("2001:4860:4860::8888", port, None, None), - ) - ] - else: - e.errno = socket.EAI_FAMILY - raise e - - -async def test_resolve(): - async def fail_with(question: dns.Question, code: int): - with pytest.raises(dns_resolver.ResolveError) as ex: - await dns_resolver.resolve_question(question, DummyLoop()) - assert ex.value.response_code == code - - async def succeed_with( - question: dns.Question, check: Callable[[dns.ResourceRecord], bool] - ): - assert any( - map(check, await dns_resolver.resolve_question(question, DummyLoop())) + assert not dr._should_resolve(f) + + +def _err(): + raise RuntimeError("failed to get name servers") + + +async def test_name_servers(caplog, monkeypatch): + dr = dns_resolver.DnsResolver() + with taddons.context(dr) as tctx: + assert dr.name_servers() == mitmproxy_rs.dns.get_system_dns_servers() + + tctx.options.dns_name_servers = ["1.1.1.1"] + assert dr.name_servers() == ["1.1.1.1"] + + monkeypatch.setattr(mitmproxy_rs.dns, "get_system_dns_servers", _err) + tctx.options.dns_name_servers = [] + assert dr.name_servers() == [] + assert "Failed to get system dns servers" in caplog.text + + +async def lookup(name: str): + match name: + case "ipv4.example.com": + return ["1.2.3.4"] + case "ipv6.example.com": + return ["::1"] + case "no-a-records.example.com": + raise socket.gaierror(socket.EAI_NODATA) + case "no-network.example.com": + raise socket.gaierror(socket.EAI_AGAIN) + case _: + raise socket.gaierror(socket.EAI_NONAME) + + +async def getaddrinfo(host: str, *_, **__): + return [[None, None, None, None, [ip]] for ip in await lookup(host)] + + +Domain = typing.Literal[ + "nxdomain.example.com", + "no-a-records.example.com", + "no-network.example.com", + "txt.example.com", + "ipv4.example.com", + "ipv6.example.com", +] +# We use literals here instead of bools because that makes the test easier to parse. +HostsFile = typing.Literal["hosts", "no-hosts"] +NameServers = typing.Literal["nameservers", "no-nameservers"] + + +@pytest.mark.parametrize("hosts_file", typing.get_args(HostsFile)) +@pytest.mark.parametrize("name_servers", typing.get_args(NameServers)) +@pytest.mark.parametrize("domain", typing.get_args(Domain)) +async def test_lookup( + domain: Domain, hosts_file: HostsFile, name_servers: NameServers, monkeypatch +): + if name_servers == "nameservers": + monkeypatch.setattr( + mitmproxy_rs.dns, "get_system_dns_servers", lambda: ["8.8.8.8"] + ) + monkeypatch.setattr( + mitmproxy_rs.dns.DnsResolver, "lookup_ipv4", lambda _, name: lookup(name) + ) + monkeypatch.setattr( + mitmproxy_rs.dns.DnsResolver, "lookup_ipv6", lambda _, name: lookup(name) + ) + else: + monkeypatch.setattr(mitmproxy_rs.dns, "get_system_dns_servers", lambda: []) + monkeypatch.setattr(asyncio.get_running_loop(), "getaddrinfo", getaddrinfo) + + dr = dns_resolver.DnsResolver() + match domain: + case "txt.example.com": + typ = dns.types.TXT + case "ipv6.example.com": + typ = dns.types.AAAA + case _: + typ = dns.types.A + + with taddons.context(dr) as tctx: + tctx.options.dns_use_hosts_file = hosts_file == "hosts" + req = tutils.tdnsreq( + questions=[ + dns.Question(domain, typ, dns.classes.IN), + ] ) + flow = tflow.tdnsflow(req=req) + await dr.dns_request(flow) - await fail_with( - dns.Question("dns.google", dns.types.A, dns.classes.CH), - dns.response_codes.NOTIMP, - ) - await fail_with( - dns.Question("not.exists", dns.types.A, dns.classes.IN), - dns.response_codes.NXDOMAIN, - ) - await fail_with( - dns.Question("dns.google", dns.types.SOA, dns.classes.IN), - dns.response_codes.NOTIMP, - ) - await fail_with( - dns.Question("totally.invalid", dns.types.PTR, dns.classes.IN), - dns.response_codes.FORMERR, - ) - await fail_with( - dns.Question("invalid.in-addr.arpa", dns.types.PTR, dns.classes.IN), - dns.response_codes.FORMERR, - ) - await fail_with( - dns.Question("0.0.0.1.in-addr.arpa", dns.types.PTR, dns.classes.IN), - dns.response_codes.NXDOMAIN, - ) - - await succeed_with( - dns.Question("dns.google", dns.types.A, dns.classes.IN), - lambda rr: rr.ipv4_address == ipaddress.IPv4Address("8.8.8.8"), - ) - await succeed_with( - dns.Question("dns.google", dns.types.AAAA, dns.classes.IN), - lambda rr: rr.ipv6_address == ipaddress.IPv6Address("2001:4860:4860::8888"), - ) - await succeed_with( - dns.Question("8.8.8.8.in-addr.arpa", dns.types.PTR, dns.classes.IN), - lambda rr: rr.domain_name == "dns.google", - ) - await succeed_with( - dns.Question( - "8.8.8.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.6.8.4.0.6.8.4.1.0.0.2.ip6.arpa", - dns.types.PTR, - dns.classes.IN, - ), - lambda rr: rr.domain_name == "dns.google", - ) - - req = tutils.tdnsreq() - req.query = False - assert ( - await dns_resolver.resolve_message(req, DummyLoop()) - ).response_code == dns.response_codes.REFUSED - req.query = True - req.op_code = dns.op_codes.IQUERY - assert ( - await dns_resolver.resolve_message(req, DummyLoop()) - ).response_code == dns.response_codes.NOTIMP - req.op_code = dns.op_codes.QUERY - resp = await dns_resolver.resolve_message(req, DummyLoop()) - assert resp.response_code == dns.response_codes.NOERROR - assert filter(lambda rr: str(rr.ipv4_address) == "8.8.8.8", resp.answers) + match (domain, name_servers, hosts_file): + case [_, "no-nameservers", "no-hosts"]: + assert flow.error + case ["nxdomain.example.com", _, _]: + assert flow.response.response_code == dns.response_codes.NXDOMAIN + case ["no-network.example.com", _, _]: + assert flow.response.response_code == dns.response_codes.SERVFAIL + case ["no-a-records.example.com", _, _]: + if sys.platform == "win32": + # On Windows, EAI_NONAME and EAI_NODATA are the same constant (11001)... + assert flow.response.response_code == dns.response_codes.NXDOMAIN + else: + assert flow.response.response_code == dns.response_codes.NOERROR + assert not flow.response.answers + case ["txt.example.com", "nameservers", _]: + assert flow.server_conn.address == ("8.8.8.8", 53) + case ["txt.example.com", "no-nameservers", _]: + assert flow.error + case ["ipv4.example.com", "nameservers", _]: + assert flow.response.answers[0].data == b"\x01\x02\x03\x04" + case ["ipv4.example.com", "no-nameservers", "hosts"]: + assert flow.response.answers[0].data == b"\x01\x02\x03\x04" + case ["ipv6.example.com", "nameservers", _]: + assert ( + flow.response.answers[0].data + == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + ) + case ["ipv6.example.com", "no-nameservers", "hosts"]: + assert ( + flow.response.answers[0].data + == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + ) + case other: + typing.assert_never(other) diff --git a/test/mitmproxy/addons/test_dumper.py b/test/mitmproxy/addons/test_dumper.py index c7f2e85d4e..9db3bd1cbd 100644 --- a/test/mitmproxy/addons/test_dumper.py +++ b/test/mitmproxy/addons/test_dumper.py @@ -97,7 +97,7 @@ def test_simple(): def test_echo_body(): f = tflow.tflow(resp=True) f.response.headers["content-type"] = "text/html" - f.response.content = b"foo bar voing\n" * 100 + f.response.content = b"foo bar voing\n" * 600 sio = io.StringIO() d = dumper.Dumper(sio) @@ -108,6 +108,21 @@ def test_echo_body(): assert "cut off" in t +def test_echo_body_custom_cutoff(): + f = tflow.tflow(resp=True) + f.response.headers["content-type"] = "text/html" + f.response.content = b"foo bar voing\n" * 4 + + sio = io.StringIO() + d = dumper.Dumper(sio) + with taddons.context(d) as ctx: + ctx.configure(d, flow_detail=3) + ctx.configure(d, content_view_lines_cutoff=3) + d._echo_message(f.response, f) + t = sio.getvalue() + assert "cut off" in t + + def test_echo_trailer(): sio = io.StringIO() d = dumper.Dumper(sio) @@ -118,7 +133,7 @@ def test_echo_trailer(): f.request.headers["content-type"] = "text/html" f.request.headers["transfer-encoding"] = "chunked" f.request.headers["trailer"] = "my-little-request-trailer" - f.request.content = b"some request content\n" * 100 + f.request.content = b"some request content\n" * 600 f.request.trailers = Headers( [(b"my-little-request-trailer", b"foobar-request-trailer")] ) @@ -291,7 +306,7 @@ def test_quic(): d = dumper.Dumper(sio) with taddons.context(d): f = tflow.ttcpflow() - f.client_conn.tls_version = "QUIC" + f.client_conn.tls_version = "QUICv1" # TODO: This should not be metadata, this should be typed attributes. f.metadata["quic_stream_id_client"] = 1 f.metadata["quic_stream_id_server"] = 1 @@ -299,7 +314,7 @@ def test_quic(): assert "quic stream 1" in sio.getvalue() f2 = tflow.tudpflow() - f2.client_conn.tls_version = "QUIC" + f2.client_conn.tls_version = "QUICv1" # TODO: This should not be metadata, this should be typed attributes. f2.metadata["quic_stream_id_client"] = 1 f2.metadata["quic_stream_id_server"] = 1 diff --git a/test/mitmproxy/addons/test_errorcheck.py b/test/mitmproxy/addons/test_errorcheck.py index b96a6dbadc..bc71f6aaf1 100644 --- a/test/mitmproxy/addons/test_errorcheck.py +++ b/test/mitmproxy/addons/test_errorcheck.py @@ -6,11 +6,13 @@ from mitmproxy.tools import main -def test_errorcheck(tdata, capsys): +@pytest.mark.parametrize("run_main", [main.mitmdump, main.mitmproxy]) +def test_errorcheck(tdata, capsys, run_main): """Integration test: Make sure that we catch errors on startup an exit.""" with pytest.raises(SystemExit): - main.mitmproxy( + run_main( [ + "-n", "-s", tdata.path("mitmproxy/data/addonscripts/load_error.py"), ] @@ -30,4 +32,12 @@ async def test_error_message(capsys): logging.error("wat") with pytest.raises(SystemExit): await e.shutdown_if_errored() - assert "Errors logged during startup" in capsys.readouterr().err + assert "Errors logged during startup, exiting..." in capsys.readouterr().err + + +async def test_repeat_error_on_stderr(capsys): + e = ErrorCheck(repeat_errors_on_stderr=True) + logging.error("wat") + with pytest.raises(SystemExit): + await e.shutdown_if_errored() + assert "Error logged during startup:\nwat" in capsys.readouterr().err diff --git a/test/mitmproxy/addons/test_export.py b/test/mitmproxy/addons/test_export.py index f3dcb8d760..af1fcdf937 100644 --- a/test/mitmproxy/addons/test_export.py +++ b/test/mitmproxy/addons/test_export.py @@ -58,6 +58,11 @@ def udp_flow(): return tflow.tudpflow() +@pytest.fixture +def websocket_flow(): + return tflow.twebsocketflow() + + @pytest.fixture(scope="module") def export_curl(): e = export.Export() @@ -217,6 +222,11 @@ def test_udp(self, udp_flow): ): export.raw(udp_flow) + def test_websocket(self, websocket_flow): + assert b"hello binary" in export.raw(websocket_flow) + assert b"hello text" in export.raw(websocket_flow) + assert b"it's me" in export.raw(websocket_flow) + class TestRawRequest: def test_get(self, get_request): @@ -286,6 +296,10 @@ def test_export(tmp_path) -> None: assert qr(f) os.unlink(f) + e.file("raw", tflow.twebsocketflow(), f) + assert qr(f) + os.unlink(f) + @pytest.mark.parametrize( "exception, log_message", diff --git a/test/mitmproxy/addons/test_intercept.py b/test/mitmproxy/addons/test_intercept.py index 0e45a28920..57b16bad13 100644 --- a/test/mitmproxy/addons/test_intercept.py +++ b/test/mitmproxy/addons/test_intercept.py @@ -89,3 +89,17 @@ async def test_udp(): f = tflow.tudpflow() await tctx.cycle(r, f) assert not f.intercepted + + +async def test_websocket_message(): + r = intercept.Intercept() + with taddons.context(r) as tctx: + tctx.configure(r, intercept='~b "hello binary"') + f = tflow.twebsocketflow() + await tctx.cycle(r, f) + assert f.intercepted + + tctx.configure(r, intercept_active=False) + f = tflow.twebsocketflow() + await tctx.cycle(r, f) + assert not f.intercepted diff --git a/test/mitmproxy/addons/test_next_layer.py b/test/mitmproxy/addons/test_next_layer.py index b91a942237..21b9ed00bd 100644 --- a/test/mitmproxy/addons/test_next_layer.py +++ b/test/mitmproxy/addons/test_next_layer.py @@ -9,10 +9,13 @@ import pytest +from mitmproxy.addons.next_layer import _starts_like_quic from mitmproxy.addons.next_layer import NeedsMoreData from mitmproxy.addons.next_layer import NextLayer from mitmproxy.addons.next_layer import stack_match +from mitmproxy.connection import Address from mitmproxy.connection import Client +from mitmproxy.connection import TlsVersion from mitmproxy.connection import TransportProtocol from mitmproxy.proxy.context import Context from mitmproxy.proxy.layer import Layer @@ -28,6 +31,7 @@ from mitmproxy.proxy.layers import UDPLayer from mitmproxy.proxy.layers.http import HTTPMode from mitmproxy.proxy.layers.http import HttpStream +from mitmproxy.proxy.layers.tls import HTTP1_ALPNS from mitmproxy.proxy.mode_specs import ProxyMode from mitmproxy.test import taddons @@ -88,55 +92,94 @@ "297c0013924e88248684fe8f2098326ce51aa6e5" ) +quic_short_header_packet = bytes.fromhex( + "52e23539dde270bb19f7a8b63b7bcf3cdacf7d3dc68a7e00318bfa2dac3bad12cb7d78112efb5bcb1ee8e0b347" + "641cccd2736577d0178b4c4c4e97a8e9e2af1d28502e58c4882223e70c4d5124c4b016855340e982c5c453d61d" + "7d0720be075fce3126de3f0d54dc059150e0f80f1a8db5e542eb03240b0a1db44a322fb4fd3c6f2e054b369e14" + "5a5ff925db617d187ec65a7f00d77651968e74c1a9ddc3c7fab57e8df821b07e103264244a3a03d17984e29933" +) + dns_query = bytes.fromhex("002a01000001000000000000076578616d706c6503636f6d0000010001") -http_query = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" +# Custom protocol with just base64-encoded messages +# https://github.com/mitmproxy/mitmproxy/pull/7087 +custom_base64_proto = b"AAAAAAAAAAAAAAAAAAAAAA==" +http_get = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" +http_get_absolute = b"GET http://example.com/ HTTP/1.1\r\n\r\n" -class TestNextLayer: - def test_configure(self): - nl = NextLayer() - with taddons.context(nl) as tctx: - with pytest.raises(Exception, match="mutually exclusive"): - tctx.configure( - nl, allow_hosts=["example.org"], ignore_hosts=["example.com"] - ) +http_connect = b"CONNECT example.com:443 HTTP/1.1\r\nHost: example.com:443\r\n\r\n" + +class TestNextLayer: @pytest.mark.parametrize( - "mode, ignore, allow, transport_protocol, server_address, data_client, result", + "ignore, allow, transport_protocol, server_address, data_client, result", [ + # ignore pytest.param( + [], [], "tcp", "example.com", b"", False, id="nothing ignored" + ), + pytest.param( + ["example.com"], [], "tcp", "example.com", b"", True, id="address" + ), + pytest.param( + ["192.0.2.1"], [], "tcp", "example.com", b"", True, id="ip address" + ), + pytest.param( + ["2001:db8::1"], [], + "tcp", + "ipv6.example.com", + b"", + True, + id="ipv6 address", + ), + pytest.param( + ["example.com:443"], [], - ["example.com"], "tcp", - "example.org", - http_query, - False, - id="extract host from http request", + "example.com", + b"", + True, + id="port matches", ), pytest.param( - ["wireguard"], - ["example.com"], + ["example.com:123"], [], - "udp", - "10.0.0.53", - dns_query, + "tcp", + "example.com", + b"", False, - id="special handling for wireguard mode", + id="port does not match", ), - # ignore pytest.param( - [], [], [], "example.com", "tcp", b"", False, id="nothing ignored" + ["example.com"], + [], + "tcp", + "192.0.2.1", + http_get, + True, + id="http host header", ), pytest.param( - [], ["example.com"], [], "tcp", "example.com", b"", True, id="address" + ["example.com"], + [], + "tcp", + "192.0.2.1", + http_get.replace(b"Host", b"X-Host"), + False, + id="http host header missing", ), pytest.param( - [], ["1.2.3.4"], [], "tcp", "example.com", b"", True, id="ip address" + ["example.com"], + [], + "tcp", + "192.0.2.1", + http_get.split(b"\r\n", 1)[0], + NeedsMoreData, + id="incomplete http host header", ), pytest.param( - [], ["example.com"], [], "tcp", @@ -146,7 +189,6 @@ def test_configure(self): id="partial address match", ), pytest.param( - [], ["example.com"], [], "tcp", @@ -156,7 +198,6 @@ def test_configure(self): id="no destination info", ), pytest.param( - [], ["example.com"], [], "tcp", @@ -166,37 +207,33 @@ def test_configure(self): id="no sni", ), pytest.param( - [], ["example.com"], [], "tcp", - None, + "192.0.2.1", client_hello_with_extensions, True, id="sni", ), pytest.param( - [], ["example.com"], [], "tcp", - None, + "192.0.2.1", client_hello_with_extensions[:-5], NeedsMoreData, id="incomplete client hello", ), pytest.param( - [], ["example.com"], [], "tcp", - None, + "192.0.2.1", client_hello_no_extensions[:9] + b"\x00" * 200, False, id="invalid client hello", ), pytest.param( - [], ["example.com"], [], "tcp", @@ -206,48 +243,43 @@ def test_configure(self): id="sni mismatch", ), pytest.param( - [], ["example.com"], [], "udp", - None, + "192.0.2.1", dtls_client_hello_with_extensions, True, id="dtls sni", ), pytest.param( - [], ["example.com"], [], "udp", - None, + "192.0.2.1", dtls_client_hello_with_extensions[:-5], NeedsMoreData, id="incomplete dtls client hello", ), pytest.param( - [], ["example.com"], [], "udp", - None, + "192.0.2.1", dtls_client_hello_with_extensions[:9] + b"\x00" * 200, False, id="invalid dtls client hello", ), pytest.param( - [], ["example.com"], [], "udp", - None, + "192.0.2.1", quic_client_hello, True, id="quic sni", ), # allow pytest.param( - [], [], ["example.com"], "tcp", @@ -257,7 +289,6 @@ def test_configure(self): id="allow: allow", ), pytest.param( - [], [], ["example.com"], "tcp", @@ -268,6 +299,23 @@ def test_configure(self): ), pytest.param( [], + ["example.com"], + "tcp", + "192.0.2.1", + client_hello_with_extensions, + False, + id="allow: sni", + ), + pytest.param( + [], + ["existing-sni.example"], + "tcp", + "192.0.2.1", + b"", + False, + id="allow: sni from parent layer", + ), + pytest.param( [], ["example.com"], "tcp", @@ -276,11 +324,29 @@ def test_configure(self): False, id="allow: sni mismatch", ), + # allow with ignore + pytest.param( + ["binary.example.com"], + ["example.com"], + "tcp", + "example.com", + b"", + False, + id="allow+ignore: allowed and not ignored", + ), + pytest.param( + ["binary.example.com"], + ["example.com"], + "tcp", + "binary.example.org", + b"", + True, + id="allow+ignore: allowed but ignored", + ), ], ) def test_ignore_connection( self, - mode: list[str], ignore: list[str], allow: list[str], transport_protocol: TransportProtocol, @@ -294,25 +360,48 @@ def test_ignore_connection( tctx.configure(nl, ignore_hosts=ignore) if allow: tctx.configure(nl, allow_hosts=allow) - if mode: - tctx.options.mode = mode ctx = Context( - Client(peername=("192.168.0.42", 51234), sockname=("0.0.0.0", 8080)), + Client( + peername=("192.168.0.42", 51234), + sockname=("0.0.0.0", 8080), + sni="existing-sni.example", + ), tctx.options, ) ctx.client.transport_protocol = transport_protocol if server_address: ctx.server.address = (server_address, 443) - ctx.server.peername = ("1.2.3.4", 443) - if "wireguard" in tctx.options.mode: - ctx.server.peername = ("10.0.0.53", 53) - ctx.server.address = ("10.0.0.53", 53) - ctx.client.proxy_mode = ProxyMode.parse("wireguard") + ctx.server.peername = ( + ("2001:db8::1", 443, 0, 0) + if server_address.startswith("ipv6") + else ("192.0.2.1", 443) + ) if result is NeedsMoreData: with pytest.raises(NeedsMoreData): - nl._ignore_connection(ctx, data_client) + nl._ignore_connection(ctx, data_client, b"") else: - assert nl._ignore_connection(ctx, data_client) is result + assert nl._ignore_connection(ctx, data_client, b"") is result + + def test_show_ignored_hosts(self, monkeypatch): + nl = NextLayer() + + with taddons.context(nl) as tctx: + m = MagicMock() + m.context = Context( + Client(peername=("192.168.0.42", 51234), sockname=("0.0.0.0", 8080)), + tctx.options, + ) + m.context.layers = [modes.TransparentProxy(m.context)] + m.context.server.address = ("example.com", 42) + tctx.configure(nl, ignore_hosts=["example.com"]) + + # Connection is ignored (not-MITM'ed) + assert nl._ignore_connection(m.context, http_get, b"") is True + # No flow is being set (i.e. nothing shown in UI) + assert nl._next_layer(m.context, http_get, b"").flow is None + # ... until `--show-ignored-hosts` is set: + tctx.configure(nl, show_ignored_hosts=True) + assert nl._next_layer(m.context, http_get, b"").flow is not None def test_next_layer(self, monkeypatch, caplog): caplog.set_level(logging.INFO) @@ -333,7 +422,7 @@ def test_next_layer(self, monkeypatch, caplog): assert m.layer is preexisting m.layer = None - monkeypatch.setattr(m, "data_client", lambda: http_query) + monkeypatch.setattr(m, "data_client", lambda: http_get) nl.next_layer(m) assert m.layer @@ -352,12 +441,15 @@ class TConf: after: list[type[Layer]] proxy_mode: str = "regular" transport_protocol: TransportProtocol = "tcp" + tls_version: TlsVersion = None data_client: bytes = b"" data_server: bytes = b"" ignore_hosts: Sequence[str] = () tcp_hosts: Sequence[str] = () udp_hosts: Sequence[str] = () ignore_conn: bool = False + server_address: Address | None = None + alpn: bytes | None = None explicit_proxy_configs = [ @@ -365,8 +457,27 @@ class TConf: TConf( before=[modes.HttpProxy], after=[modes.HttpProxy, HttpLayer], + data_client=http_connect, + ), + id=f"explicit proxy: regular http connect", + ), + pytest.param( + TConf( + before=[modes.HttpProxy], + after=[modes.HttpProxy, HttpLayer], + ignore_hosts=[".+"], + data_client=http_connect, ), - id=f"explicit proxy: regular http", + id=f"explicit proxy: regular http connect disregards ignore_hosts", + ), + pytest.param( + TConf( + before=[modes.HttpProxy], + after=[modes.HttpProxy, HttpLayer], + ignore_hosts=[".+"], + data_client=http_get_absolute, + ), + id=f"explicit proxy: HTTP over regular proxy disregards ignore_hosts", ), pytest.param( TConf( @@ -450,7 +561,7 @@ class TConf: partial(HttpStream, stream_id=1), ], after=[modes.HttpProxy, HttpLayer, HttpStream, TCPLayer], - data_client=b"\xFF", + data_client=b"\xff", ), id=f"explicit proxy: TCP over regular proxy", ), @@ -522,13 +633,21 @@ class TConf: id="reverse proxy: dns", ), pytest.param( - TConf( + http3 := TConf( before=[modes.ReverseProxy], after=[modes.ReverseProxy, ServerQuicLayer, ClientQuicLayer, HttpLayer], proxy_mode="reverse:http3://example.com", ), id="reverse proxy: http3", ), + pytest.param( + dataclasses.replace( + http3, + proxy_mode="reverse:https://example.com", + transport_protocol="udp", + ), + id="reverse proxy: http3 in https mode", + ), pytest.param( TConf( before=[modes.ReverseProxy], @@ -542,6 +661,18 @@ class TConf: ), id="reverse proxy: quic", ), + pytest.param( + TConf( + before=[modes.ReverseProxy], + after=[modes.ReverseProxy, TCPLayer], + proxy_mode=f"reverse:http://example.com", + ignore_hosts=["example.com"], + server_address=("example.com", 80), + data_client=http_get, + ignore_conn=True, + ), + id="reverse proxy: ignore_hosts", + ), ] ) @@ -564,14 +695,22 @@ class TConf: id=f"transparent proxy: dtls", ), pytest.param( - TConf( + quic := TConf( before=[modes.TransparentProxy], after=[modes.TransparentProxy, ServerQuicLayer, ClientQuicLayer], data_client=quic_client_hello, transport_protocol="udp", + server_address=("192.0.2.1", 443), ), id="transparent proxy: quic", ), + pytest.param( + dataclasses.replace( + quic, + data_client=quic_short_header_packet, + ), + id="transparent proxy: existing quic session", + ), pytest.param( TConf( before=[modes.TransparentProxy], @@ -584,14 +723,33 @@ class TConf: http := TConf( before=[modes.TransparentProxy], after=[modes.TransparentProxy, HttpLayer], - data_client=b"GET / HTTP/1.1\r\n", + server_address=("192.0.2.1", 80), + data_client=http_get, ), id="transparent proxy: http", ), + pytest.param( + TConf( + before=[modes.TransparentProxy, ServerTLSLayer, ClientTLSLayer], + after=[modes.TransparentProxy, ServerTLSLayer, ClientTLSLayer, HttpLayer], + data_client=b"GO /method-too-short-for-heuristic HTTP/1.1\r\n", + alpn=HTTP1_ALPNS[0], + ), + id=f"transparent proxy: http via ALPN", + ), + pytest.param( + TConf( + before=[modes.TransparentProxy], + after=[modes.TransparentProxy, TCPLayer], + server_address=("192.0.2.1", 23), + data_client=b"SSH-2.0-OpenSSH_9.7", + ), + id="transparent proxy: ssh", + ), pytest.param( dataclasses.replace( http, - tcp_hosts=["example.com"], + tcp_hosts=["192.0.2.1"], after=[modes.TransparentProxy, TCPLayer], ), id="transparent proxy: tcp_hosts", @@ -599,38 +757,81 @@ class TConf: pytest.param( dataclasses.replace( http, - ignore_hosts=["example.com"], + ignore_hosts=["192.0.2.1"], after=[modes.TransparentProxy, TCPLayer], ignore_conn=True, ), id="transparent proxy: ignore_hosts", ), pytest.param( - dns := TConf( + TConf( before=[modes.TransparentProxy], - after=[modes.TransparentProxy, DNSLayer], - transport_protocol="udp", - data_client=dns_query, + after=[modes.TransparentProxy, TCPLayer], + data_client=custom_base64_proto, ), - id="transparent proxy: dns", + id="transparent proxy: full alpha tcp", ), pytest.param( - TConf( + udp := TConf( before=[modes.TransparentProxy], after=[modes.TransparentProxy, UDPLayer], + server_address=("192.0.2.1", 553), transport_protocol="udp", - data_client=b"\xFF", + data_client=b"\xff", ), id="transparent proxy: raw udp", ), + pytest.param( + dns := dataclasses.replace( + udp, + after=[modes.TransparentProxy, DNSLayer], + data_client=dns_query, + server_address=("192.0.2.1", 53), + ), + id="transparent proxy: dns over udp", + ), pytest.param( dataclasses.replace( dns, - udp_hosts=["example.com"], + transport_protocol="tcp", + ), + id="transparent proxy: dns over tcp", + ), + pytest.param( + dataclasses.replace( + udp, + udp_hosts=["192.0.2.1"], after=[modes.TransparentProxy, UDPLayer], ), id="transparent proxy: udp_hosts", ), + pytest.param( + TConf( + before=[modes.TransparentProxy], + after=[modes.TransparentProxy, DNSLayer], + proxy_mode="wireguard", + server_address=("10.0.0.53", 53), + ignore_hosts=[".+"], + transport_protocol="udp", + data_client=dns_query, + ), + id="wireguard proxy: dns should not be ignored", + ), + pytest.param( + TConf( + before=[modes.TransparentProxy, ServerQuicLayer, ClientQuicLayer], + after=[ + modes.TransparentProxy, + ServerQuicLayer, + ClientQuicLayer, + RawQuicLayer, + ], + data_client=b"", + alpn=b"doq", + tls_version="QUICv1", + ), + id=f"transparent proxy: non-http quic", + ), ] @@ -655,12 +856,16 @@ def test_next_layer( ) ctx = Context( - Client(peername=("192.168.0.42", 51234), sockname=("0.0.0.0", 8080)), + Client( + peername=("192.168.0.42", 51234), + sockname=("0.0.0.0", 8080), + alpn=test_conf.alpn, + ), tctx.options, ) - ctx.server.address = ("example.com", 42) - # these aren't properly set up, but this does not matter here. + ctx.server.address = test_conf.server_address ctx.client.transport_protocol = test_conf.transport_protocol + ctx.client.tls_version = test_conf.tls_version ctx.client.proxy_mode = ProxyMode.parse(test_conf.proxy_mode) ctx.layers = [x(ctx) for x in test_conf.before] nl._next_layer( @@ -668,8 +873,24 @@ def test_next_layer( data_client=test_conf.data_client, data_server=test_conf.data_server, ) - assert stack_match(ctx, test_conf.after) + assert stack_match(ctx, test_conf.after), f"Unexpected stack: {ctx.layers}" last_layer = ctx.layers[-1] if isinstance(last_layer, (UDPLayer, TCPLayer)): assert bool(last_layer.flow) ^ test_conf.ignore_conn + + +def test_starts_like_quic(): + assert not _starts_like_quic(b"", ("192.0.2.1", 443)) + assert not _starts_like_quic(dtls_client_hello_with_extensions, ("192.0.2.1", 443)) + + # Long Header - we can get definite answers from version numbers. + assert _starts_like_quic(quic_client_hello, None) + quic_version_negotation_grease = bytes.fromhex( + "ca0a0a0a0a08c0618c84b54541320823fcce946c38d8210044e6a93bbb283593f75ffb6f2696b16cfdcb5b1255" + ) + assert _starts_like_quic(quic_version_negotation_grease, None) + + # Short Header - port-based is the best we can do. + assert _starts_like_quic(quic_short_header_packet, ("192.0.2.1", 443)) + assert not _starts_like_quic(quic_short_header_packet, ("192.0.2.1", 444)) diff --git a/test/mitmproxy/addons/test_proxyauth.py b/test/mitmproxy/addons/test_proxyauth.py index 743bc635bf..e715e9d11d 100644 --- a/test/mitmproxy/addons/test_proxyauth.py +++ b/test/mitmproxy/addons/test_proxyauth.py @@ -239,6 +239,11 @@ def test_handlers(self): assert not f2.response assert f2.metadata["proxyauth"] == ("test", "test") + f3 = tflow.tflow() + f3.is_replay = True + up.requestheaders(f3) + assert not f2.response + @pytest.mark.parametrize( "spec", diff --git a/test/mitmproxy/addons/test_proxyserver.py b/test/mitmproxy/addons/test_proxyserver.py index 341bfbe091..eccc98f1ee 100644 --- a/test/mitmproxy/addons/test_proxyserver.py +++ b/test/mitmproxy/addons/test_proxyserver.py @@ -1,7 +1,6 @@ from __future__ import annotations import asyncio -import socket import ssl from collections.abc import AsyncGenerator from collections.abc import Callable @@ -23,7 +22,9 @@ from aioquic.quic.connection import QuicConnection from aioquic.quic.connection import QuicConnectionError +from .test_clientplayback import tcp_server import mitmproxy.platform +import mitmproxy_rs from mitmproxy import dns from mitmproxy import exceptions from mitmproxy.addons import dns_resolver @@ -31,7 +32,6 @@ from mitmproxy.addons.proxyserver import Proxyserver from mitmproxy.addons.tlsconfig import TlsConfig from mitmproxy.connection import Address -from mitmproxy.net import udp from mitmproxy.proxy import layers from mitmproxy.proxy import server_hooks from mitmproxy.test import taddons @@ -55,16 +55,6 @@ def tcp_start(self, f): self.flows.append(f) -@asynccontextmanager -async def tcp_server(handle_conn) -> Address: - server = await asyncio.start_server(handle_conn, "127.0.0.1", 0) - await server.start_serving() - try: - yield server.sockets[0].getsockname() - finally: - server.close() - - async def test_start_stop(caplog_async): caplog_async.set_level("INFO") @@ -74,7 +64,6 @@ async def server_handler( assert await reader.readuntil(b"\r\n\r\n") == b"GET /hello HTTP/1.1\r\n\r\n" writer.write(b"HTTP/1.1 204 No Content\r\n\r\n") await writer.drain() - writer.close() ps = Proxyserver() nl = NextLayer() @@ -112,19 +101,27 @@ async def server_handler( assert state.flows[0].request.path == "/hello" assert state.flows[0].response.status_code == 204 - # Waiting here until everything is really torn down... takes some effort. - conn_handler = list(ps.connections.values())[0] - client_handler = conn_handler.transports[conn_handler.client].handler writer.close() await writer.wait_closed() - try: - await client_handler - except asyncio.CancelledError: - pass - for _ in range(5): - # Get all other scheduled coroutines to run. - await asyncio.sleep(0) - assert repr(ps) == "Proxyserver(0 active conns)" + await _wait_for_connection_closes(ps) + + +async def _wait_for_connection_closes(ps: Proxyserver): + # Waiting here until everything is really torn down... takes some effort. + client_handlers = [ + conn_handler.transports[conn_handler.client].handler + for conn_handler in ps.connections.values() + if conn_handler.client in conn_handler.transports + ] + for client_handler in client_handlers: + try: + await asyncio.wait_for(client_handler, 5) + except asyncio.CancelledError: + pass + for _ in range(5): + # Get all other scheduled coroutines to run. + await asyncio.sleep(0) + assert not ps.connections async def test_inject() -> None: @@ -160,6 +157,10 @@ async def server_handler( ps.inject_tcp(state.flows[0], True, b"c") assert await reader.read(1) == b"c" + writer.close() + await writer.wait_closed() + await _wait_for_connection_closes(ps) + async def test_inject_fail(caplog) -> None: ps = Proxyserver() @@ -207,6 +208,7 @@ async def test_self_connect(): assert "Request destination unknown" in server.error tctx.configure(ps, server=False) assert await ps.setup_servers() + await _wait_for_connection_closes(ps) def test_options(): @@ -229,7 +231,7 @@ def test_options(): tctx.configure(ps, mode=["invalid!"]) with pytest.raises(exceptions.OptionsError): tctx.configure(ps, mode=["regular", "reverse:example.com"]) - tctx.configure(ps, mode=["regular"], server=False) + tctx.configure(ps, mode=["regular", "local"], server=False) async def test_startup_err(monkeypatch, caplog) -> None: @@ -260,24 +262,21 @@ async def _raise(*_): setattr(server, "stop", _raise) tctx.configure(ps, server=False) await caplog_async.await_log("cannot close") + await _wait_for_connection_closes(ps) -class DummyResolver: - async def dns_request(self, flow: dns.DNSFlow) -> None: - flow.response = await dns_resolver.resolve_message(flow.request, self) +async def lookup_ipv4(): + return await asyncio.sleep(0, ["8.8.8.8"]) - async def getaddrinfo(self, host: str, port: int, *, family: int): - if family == socket.AF_INET and host == "dns.google": - return [(socket.AF_INET, None, None, None, ("8.8.8.8", port))] - e = socket.gaierror() - e.errno = socket.EAI_NONAME - raise e +async def test_dns(caplog_async, monkeypatch) -> None: + monkeypatch.setattr( + mitmproxy_rs.dns.DnsResolver, "lookup_ipv4", lambda _, __: lookup_ipv4() + ) -async def test_dns(caplog_async) -> None: caplog_async.set_level("INFO") ps = Proxyserver() - with taddons.context(ps, DummyResolver()) as tctx: + with taddons.context(ps, dns_resolver.DnsResolver()) as tctx: tctx.configure( ps, mode=["dns@127.0.0.1:0"], @@ -287,30 +286,34 @@ async def test_dns(caplog_async) -> None: await caplog_async.await_log("DNS server listening at") assert ps.servers dns_addr = ps.servers["dns@127.0.0.1:0"].listen_addrs[0] - r, w = await udp.open_connection(*dns_addr) + s = await mitmproxy_rs.udp.open_udp_connection(*dns_addr) req = tdnsreq() - w.write(req.packed) - resp = dns.Message.unpack(await r.read(udp.MAX_DATAGRAM_SIZE)) + s.write(req.packed) + resp = dns.Message.unpack(await s.read(65535)) assert req.id == resp.id and "8.8.8.8" in str(resp) assert len(ps.connections) == 1 - w.write(req.packed) - resp = dns.Message.unpack(await r.read(udp.MAX_DATAGRAM_SIZE)) + s.write(req.packed) + resp = dns.Message.unpack(await s.read(65535)) assert req.id == resp.id and "8.8.8.8" in str(resp) assert len(ps.connections) == 1 req.id = req.id + 1 - w.write(req.packed) - resp = dns.Message.unpack(await r.read(udp.MAX_DATAGRAM_SIZE)) + s.write(req.packed) + resp = dns.Message.unpack(await s.read(65535)) assert req.id == resp.id and "8.8.8.8" in str(resp) assert len(ps.connections) == 1 - dns_layer = ps.connections[(w.get_extra_info("sockname"), dns_addr)].layer - assert isinstance(dns_layer, layers.DNSLayer) - assert len(dns_layer.flows) == 2 + (dns_conn,) = ps.connections.values() + assert isinstance(dns_conn.layer, layers.DNSLayer) + assert len(dns_conn.layer.flows) == 2 - w.write(b"\x00") + s.write(b"\x00") await caplog_async.await_log("sent an invalid message") tctx.configure(ps, server=False) await caplog_async.await_log("stopped") + s.close() + await s.wait_closed() + await _wait_for_connection_closes(ps) + def test_validation_no_transparent(monkeypatch): monkeypatch.setattr(mitmproxy.platform, "original_addr", None) @@ -331,22 +334,38 @@ def test_transparent_init(monkeypatch): @asynccontextmanager -async def udp_server(handle_conn) -> Address: - server = await udp.start_server(handle_conn, "127.0.0.1", 0) +async def udp_server( + handle_datagram: Callable[ + [asyncio.DatagramTransport, bytes, tuple[str, int]], None + ], +) -> Address: + class ServerProtocol(asyncio.DatagramProtocol): + def connection_made(self, transport): + self.transport = transport + + def datagram_received(self, data, addr): + handle_datagram(self.transport, data, addr) + + loop = asyncio.get_running_loop() + transport, _ = await loop.create_datagram_endpoint( + lambda: ServerProtocol(), + local_addr=("127.0.0.1", 0), + ) + socket = transport.get_extra_info("socket") + try: - yield server.sockets[0].getsockname() + yield socket.getsockname() finally: - server.close() + transport.close() async def test_udp(caplog_async) -> None: caplog_async.set_level("INFO") - def server_handler( + def handle_datagram( transport: asyncio.DatagramTransport, data: bytes, remote_addr: Address, - _: Address, ): assert data == b"\x16" transport.sendto(b"\x01", remote_addr) @@ -355,7 +374,7 @@ def server_handler( nl = NextLayer() with taddons.context(ps, nl) as tctx: - async with udp_server(server_handler) as server_addr: + async with udp_server(handle_datagram) as server_addr: mode = f"reverse:udp://{server_addr[0]}:{server_addr[1]}@127.0.0.1:0" tctx.configure(ps, mode=[mode]) assert await ps.setup_servers() @@ -365,14 +384,18 @@ def server_handler( ) assert ps.servers addr = ps.servers[mode].listen_addrs[0] - r, w = await udp.open_connection(*addr) - w.write(b"\x16") - assert b"\x01" == await r.read(udp.MAX_DATAGRAM_SIZE) + stream = await mitmproxy_rs.udp.open_udp_connection(*addr) + stream.write(b"\x16") + assert b"\x01" == await stream.read(65535) assert repr(ps) == "Proxyserver(1 active conns)" assert len(ps.connections) == 1 tctx.configure(ps, server=False) await caplog_async.await_log("stopped") + stream.close() + await stream.wait_closed() + await _wait_for_connection_closes(ps) + class H3EchoServer(QuicConnectionProtocol): def __init__(self, *args, **kwargs) -> None: @@ -468,7 +491,7 @@ async def quic_server( class QuicClient(QuicConnectionProtocol): - TIMEOUT: ClassVar[int] = 5 + TIMEOUT: ClassVar[int] = 10 def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) @@ -746,18 +769,14 @@ def assert_no_data(response: H3Response): assert r5.trailers == [(b"x-response", b"everything but end_stream")] -@pytest.mark.parametrize("connection_strategy", ["lazy", "eager"]) @pytest.mark.parametrize("scheme", ["http3", "quic"]) -async def test_reverse_http3_and_quic_stream( - caplog_async, scheme: str, connection_strategy: str -) -> None: +async def test_reverse_http3_and_quic_stream(caplog_async, scheme: str) -> None: caplog_async.set_level("INFO") ps = Proxyserver() nl = NextLayer() ta = TlsConfig() with taddons.context(ps, nl, ta) as tctx: tctx.options.keep_host_header = True - tctx.options.connection_strategy = connection_strategy ta.configure(["confdir"]) async with quic_server(H3EchoServer, alpn=["h3"]) as server_addr: mode = f"reverse:{scheme}://{server_addr[0]}:{server_addr[1]}@127.0.0.1:0" @@ -781,17 +800,16 @@ async def test_reverse_http3_and_quic_stream( tctx.configure(ps, server=False) await caplog_async.await_log(f"stopped") + await _wait_for_connection_closes(ps) -@pytest.mark.parametrize("connection_strategy", ["lazy", "eager"]) -async def test_reverse_quic_datagram(caplog_async, connection_strategy: str) -> None: +async def test_reverse_quic_datagram(caplog_async) -> None: caplog_async.set_level("INFO") ps = Proxyserver() nl = NextLayer() ta = TlsConfig() with taddons.context(ps, nl, ta) as tctx: tctx.options.keep_host_header = True - tctx.options.connection_strategy = connection_strategy ta.configure(["confdir"]) async with quic_server(QuicDatagramEchoServer, alpn=["dgram"]) as server_addr: mode = f"reverse:quic://{server_addr[0]}:{server_addr[1]}@127.0.0.1:0" @@ -817,6 +835,7 @@ async def test_reverse_quic_datagram(caplog_async, connection_strategy: str) -> tctx.configure(ps, server=False) await caplog_async.await_log("stopped") + await _wait_for_connection_closes(ps) @pytest.mark.skip("HTTP/3 for regular mode is not fully supported yet") @@ -828,17 +847,19 @@ async def test_regular_http3(caplog_async, monkeypatch) -> None: with taddons.context(ps, nl, ta) as tctx: ta.configure(["confdir"]) async with quic_server(H3EchoServer, alpn=["h3"]) as server_addr: - orig_open_connection = udp.open_connection + orig_open_connection = mitmproxy_rs.udp.open_udp_connection - def open_connection_path( + async def open_connection_path( host: str, port: int, *args, **kwargs - ) -> udp.UdpClient: + ) -> mitmproxy_rs.Stream: if host == "example.mitmproxy.org" and port == 443: host = server_addr[0] port = server_addr[1] return orig_open_connection(host, port, *args, **kwargs) - monkeypatch.setattr(udp, "open_connection", open_connection_path) + monkeypatch.setattr( + mitmproxy_rs.udp, "open_udp_connection", open_connection_path + ) mode = f"http3@127.0.0.1:0" tctx.configure( ta, @@ -858,3 +879,4 @@ def open_connection_path( tctx.configure(ps, server=False) await caplog_async.await_log("stopped") + await _wait_for_connection_closes(ps) diff --git a/test/mitmproxy/addons/test_readfile.py b/test/mitmproxy/addons/test_readfile.py index 78513d586c..bc1dd383a9 100644 --- a/test/mitmproxy/addons/test_readfile.py +++ b/test/mitmproxy/addons/test_readfile.py @@ -54,13 +54,21 @@ async def test_read(self, tmpdir, data, corrupt_data, caplog_async): tf = tmpdir.join("tfile") - with mock.patch("mitmproxy.master.Master.load_flow") as mck: - tf.write(data.getvalue()) - tctx.configure(rf, rfile=str(tf), readfile_filter=".*") - mck.assert_not_awaited() - rf.running() + load_called = asyncio.Event() + + async def load_flow(*_, **__): + load_called.set() + + tctx.master.load_flow = load_flow + + tf.write(data.getvalue()) + tctx.configure(rf, rfile=str(tf), readfile_filter=".*") + assert not load_called.is_set() + rf.running() + await load_called.wait() + + while rf.reading(): await asyncio.sleep(0) - mck.assert_awaited() tf.write(corrupt_data.getvalue()) tctx.configure(rf, rfile=str(tf)) diff --git a/test/mitmproxy/addons/test_savehar.py b/test/mitmproxy/addons/test_savehar.py index c725ece55c..753938fde6 100644 --- a/test/mitmproxy/addons/test_savehar.py +++ b/test/mitmproxy/addons/test_savehar.py @@ -141,12 +141,12 @@ def test_tls_setup(): flow = tflow.twebsocketflow() flow.server_conn.timestamp_tls_setup = None - assert s.flow_entry(flow, servers_seen)["timings"]["ssl"] is None + assert s.flow_entry(flow, servers_seen)["timings"]["ssl"] == -1.0 def test_binary_content(): resp_content = SaveHar().make_har( - [tflow.tflow(resp=tutils.tresp(content=b"foo" + b"\xFF" * 10))] + [tflow.tflow(resp=tutils.tresp(content=b"foo" + b"\xff" * 10))] )["log"]["entries"][0]["response"]["content"] assert resp_content == { "compression": 0, @@ -173,6 +173,18 @@ def test_savehar(log_file: Path, tmp_path: Path, monkeypatch): assert actual_har == expected_har +def test_flow_entry(): + """https://github.com/mitmproxy/mitmproxy/issues/6579""" + s = SaveHar() + req = Request.make("CONNECT", "https://test.test/") + flow = tflow.tflow(req=req) + servers_seen: set[Server] = set() + + flow_entry = s.flow_entry(flow, servers_seen) + + assert flow_entry["request"]["url"].startswith("https") + + class TestHardumpOption: def test_simple(self, capsys): s = SaveHar() diff --git a/test/mitmproxy/addons/test_script.py b/test/mitmproxy/addons/test_script.py index add0801fbe..e2dfc0b2b9 100644 --- a/test/mitmproxy/addons/test_script.py +++ b/test/mitmproxy/addons/test_script.py @@ -25,7 +25,7 @@ def test_load_script(tmp_path, tdata, caplog): assert ns.addons script.load_script("nonexistent") - assert "No such file or directory" in caplog.text + assert "FileNotFoundError" in caplog.text (tmp_path / "error.py").write_text("this is invalid syntax") script.load_script(str(tmp_path / "error.py")) @@ -328,6 +328,7 @@ def test_order(tdata, capsys): ] ) time = r"\[[\d:.]+\] " + out = capsys.readouterr().out assert re.match( rf"{time}Loading script.+recorder.py\n" rf"{time}\('recorder', 'load', .+\n" @@ -335,5 +336,5 @@ def test_order(tdata, capsys): rf"{time}Loading script.+shutdown.py\n" rf"{time}\('recorder', 'running', .+\n" rf"{time}\('recorder', 'done', .+\n$", - capsys.readouterr().out, + out, ) diff --git a/test/mitmproxy/addons/test_serverplayback.py b/test/mitmproxy/addons/test_serverplayback.py index aa3a2178de..7ae12c2eed 100644 --- a/test/mitmproxy/addons/test_serverplayback.py +++ b/test/mitmproxy/addons/test_serverplayback.py @@ -325,6 +325,24 @@ def multipart_setter(r, **kwargs): thash(r, r2, multipart_setter) +def test_runtime_modify_params(): + s = serverplayback.ServerPlayback() + with taddons.context(s) as tctx: + r = tflow.tflow(resp=True) + r.request.path = "/test?param1=1" + r2 = tflow.tflow(resp=True) + r2.request.path = "/test" + + s.load_flows([r]) + hash = next(iter(s.flowmap.keys())) + + tctx.configure(s, server_replay_ignore_params=["param1"]) + hash_mod = next(iter(s.flowmap.keys())) + + assert hash != hash_mod + assert hash_mod == s._hash(r2) + + def test_server_playback_full(): s = serverplayback.ServerPlayback() with taddons.context(s) as tctx: diff --git a/test/mitmproxy/addons/test_stickycookie.py b/test/mitmproxy/addons/test_stickycookie.py index 906087c0d2..687deaf09d 100644 --- a/test/mitmproxy/addons/test_stickycookie.py +++ b/test/mitmproxy/addons/test_stickycookie.py @@ -121,9 +121,9 @@ def test_response_delete(self): # Test that a cookie is be deleted # by setting the expire time in the past f = self._response(sc, "duffer=zafar; Path=/", "www.google.com") - f.response.headers[ - "Set-Cookie" - ] = "duffer=; Expires=Thu, 01-Jan-1970 00:00:00 GMT" + f.response.headers["Set-Cookie"] = ( + "duffer=; Expires=Thu, 01-Jan-1970 00:00:00 GMT" + ) sc.response(f) assert not sc.jar.keys() diff --git a/test/mitmproxy/addons/test_strip_dns_https_records.py b/test/mitmproxy/addons/test_strip_dns_https_records.py new file mode 100644 index 0000000000..1c80f78dca --- /dev/null +++ b/test/mitmproxy/addons/test_strip_dns_https_records.py @@ -0,0 +1,85 @@ +from mitmproxy import dns +from mitmproxy.addons import strip_dns_https_records +from mitmproxy.net.dns import https_records +from mitmproxy.net.dns import types +from mitmproxy.net.dns.https_records import SVCParamKeys +from mitmproxy.test import taddons +from mitmproxy.test import tflow +from mitmproxy.test import tutils + + +class TestStripECH: + def test_strip_ech(self): + se = strip_dns_https_records.StripDnsHttpsRecords() + with taddons.context(se) as tctx: + params1 = { + SVCParamKeys.PORT.value: b"\x01\xbb", + SVCParamKeys.ECH.value: b"testbytes", + } + params2 = {SVCParamKeys.PORT.value: b"\x01\xbb"} + record1 = https_records.HTTPSRecord(1, "example.com", params1) + record2 = https_records.HTTPSRecord(1, "example.com", params2) + answers = [ + dns.ResourceRecord( + "dns.google", + dns.types.A, + dns.classes.IN, + 32, + b"\x08\x08\x08\x08", + ), + dns.ResourceRecord( + "dns.google", + dns.types.HTTPS, + dns.classes.IN, + 32, + https_records.pack(record1), + ), + dns.ResourceRecord( + "dns.google", + dns.types.HTTPS, + dns.classes.IN, + 32, + https_records.pack(record2), + ), + ] + resp = tutils.tdnsresp(answers=answers) + f = tflow.tdnsflow(resp=resp) + tctx.configure(se, strip_ech=True) + se.dns_response(f) + assert all( + answer.https_ech is None + for answer in f.response.answers + if answer.type == types.HTTPS + ) + + def test_strip_alpn(self): + se = strip_dns_https_records.StripDnsHttpsRecords() + with taddons.context(se) as tctx: + record2 = https_records.HTTPSRecord( + 1, + "example.com", + { + SVCParamKeys.ALPN.value: b"\x02h2\x02h3", + }, + ) + answers = [ + dns.ResourceRecord( + "dns.google", + dns.types.HTTPS, + dns.classes.IN, + 32, + https_records.pack(record2), + ) + ] + f = tflow.tdnsflow(resp=tutils.tdnsresp(answers=answers)) + + se.dns_response(f) + assert f.response.answers[0].https_alpn == (b"h2", b"h3") + + tctx.configure(se, http3=False) + se.dns_response(f) + assert f.response.answers[0].https_alpn == (b"h2",) + + f.response.answers[0].https_alpn = [b"h3"] + se.dns_response(f) + assert f.response.answers[0].https_alpn is None diff --git a/test/mitmproxy/addons/test_tlsconfig.py b/test/mitmproxy/addons/test_tlsconfig.py index 64144e12e5..49584f2ee8 100644 --- a/test/mitmproxy/addons/test_tlsconfig.py +++ b/test/mitmproxy/addons/test_tlsconfig.py @@ -1,3 +1,5 @@ +import ipaddress +import logging import ssl import time from pathlib import Path @@ -16,8 +18,8 @@ from mitmproxy.proxy.layers import quic from mitmproxy.proxy.layers import tls as proxy_tls from mitmproxy.test import taddons -from test.mitmproxy.proxy.layers import test_quic from test.mitmproxy.proxy.layers import test_tls +from test.mitmproxy.proxy.layers.quic import test__stream_layers as test_quic def test_alpn_select_callback(): @@ -106,6 +108,29 @@ def test_configure(self, tdata): ) assert ta.certstore.certs + def test_configure_tls_version(self, caplog): + caplog.set_level(logging.INFO) + ta = tlsconfig.TlsConfig() + with taddons.context(ta) as tctx: + for attr in [ + "tls_version_client_min", + "tls_version_client_max", + "tls_version_server_min", + "tls_version_server_max", + ]: + caplog.clear() + tctx.configure(ta, **{attr: "SSL3"}) + assert ( + f"{attr} has been set to SSL3, " + "which is not supported by the current OpenSSL build." + ) in caplog.text + caplog.clear() + tctx.configure(ta, tls_version_client_min="UNBOUNDED") + assert ( + "tls_version_client_min has been set to UNBOUNDED. " + "Note that your OpenSSL build only supports the following TLS versions" + ) in caplog.text + def test_get_cert(self, tdata): """Test that we generate a certificate matching the connection's context.""" ta = tlsconfig.TlsConfig() @@ -128,26 +153,28 @@ def test_get_cert(self, tdata): ctx.server.certificate_list = [certs.Cert.from_pem(f.read())] entry = ta.get_cert(ctx) assert entry.cert.cn == "example.mitmproxy.org" - assert entry.cert.altnames == [ - "example.mitmproxy.org", - "server-address.example", - "127.0.0.1", - ] + assert entry.cert.altnames == x509.GeneralNames( + [ + x509.DNSName("example.mitmproxy.org"), + x509.IPAddress(ipaddress.ip_address("127.0.0.1")), + x509.DNSName("server-address.example"), + ] + ) # And now we also incorporate SNI. - ctx.client.sni = "sni.example" + ctx.client.sni = "🌈.sni.example" entry = ta.get_cert(ctx) - assert entry.cert.altnames == [ - "example.mitmproxy.org", - "sni.example", - "server-address.example", - ] + assert entry.cert.altnames == x509.GeneralNames( + [ + x509.DNSName("example.mitmproxy.org"), + x509.DNSName("xn--og8h.sni.example"), + x509.DNSName("server-address.example"), + ] + ) with open(tdata.path("mitmproxy/data/invalid-subject.pem"), "rb") as f: ctx.server.certificate_list = [certs.Cert.from_pem(f.read())] - with pytest.warns( - UserWarning, match="Country names should be two characters" - ): + with pytest.warns(UserWarning): assert ta.get_cert(ctx) # does not raise def test_tls_clienthello(self): @@ -384,12 +411,14 @@ def assert_alpn(http2, client_offers, expected): assert ctx.server.alpn_offers == expected assert_alpn( - True, proxy_tls.HTTP_ALPNS + (b"foo",), proxy_tls.HTTP_ALPNS + (b"foo",) + True, + (proxy_tls.HTTP2_ALPN, *proxy_tls.HTTP1_ALPNS, b"foo"), + (proxy_tls.HTTP2_ALPN, *proxy_tls.HTTP1_ALPNS, b"foo"), ) assert_alpn( False, - proxy_tls.HTTP_ALPNS + (b"foo",), - proxy_tls.HTTP1_ALPNS + (b"foo",), + (proxy_tls.HTTP2_ALPN, *proxy_tls.HTTP1_ALPNS, b"foo"), + (*proxy_tls.HTTP1_ALPNS, b"foo"), ) assert_alpn(True, [], []) assert_alpn(False, [], []) diff --git a/test/mitmproxy/addons/test_update_alt_svc.py b/test/mitmproxy/addons/test_update_alt_svc.py new file mode 100644 index 0000000000..e0509d2e80 --- /dev/null +++ b/test/mitmproxy/addons/test_update_alt_svc.py @@ -0,0 +1,44 @@ +from mitmproxy import http +from mitmproxy.addons import update_alt_svc +from mitmproxy.proxy.mode_specs import ProxyMode +from mitmproxy.test import taddons +from mitmproxy.test import tflow + + +def test_simple(): + header = 'h3="example.com:443"; ma=3600, h2=":443"; ma=3600' + modified = update_alt_svc.update_alt_svc_header(header, 1234) + assert modified == 'h3=":1234"; ma=3600, h2=":1234"; ma=3600' + + +def test_updates_alt_svc_header(): + upd = update_alt_svc.UpdateAltSvc() + with taddons.context(upd) as ctx: + headers = http.Headers( + host="example.com", + content_type="application/xml", + alt_svc='h3="example.com:443"; ma=3600, h2=":443"; ma=3600', + ) + resp = tflow.tresp(headers=headers) + f = tflow.tflow(resp=resp) + f.client_conn.sockname = ("", 1234) + + upd.responseheaders(f) + assert ( + f.response.headers["alt-svc"] + == 'h3="example.com:443"; ma=3600, h2=":443"; ma=3600' + ) + + ctx.options.keep_alt_svc_header = True + f.client_conn.proxy_mode = ProxyMode.parse("reverse:https://example.com") + upd.responseheaders(f) + assert ( + f.response.headers["alt-svc"] + == 'h3="example.com:443"; ma=3600, h2=":443"; ma=3600' + ) + + ctx.options.keep_alt_svc_header = False + upd.responseheaders(f) + assert ( + f.response.headers["alt-svc"] == 'h3=":1234"; ma=3600, h2=":1234"; ma=3600' + ) diff --git a/test/mitmproxy/addons/test_view.py b/test/mitmproxy/addons/test_view.py index 7e76a83eea..5ee0873c8f 100644 --- a/test/mitmproxy/addons/test_view.py +++ b/test/mitmproxy/addons/test_view.py @@ -682,7 +682,7 @@ def test_configure(): [ [":default:", SYMBOL_MARK], ["X", "X"], - [":grapes:", "\N{grapes}"], + [":grapes:", "\N{GRAPES}"], [":not valid:", SYMBOL_MARK], [":weird", SYMBOL_MARK], ], diff --git a/test/mitmproxy/contentviews/test_api.py b/test/mitmproxy/contentviews/test_api.py index c943610b07..259343fab3 100644 --- a/test/mitmproxy/contentviews/test_api.py +++ b/test/mitmproxy/contentviews/test_api.py @@ -81,6 +81,18 @@ def test_get_message_content_view(): desc, lines, err = contentviews.get_message_content_view("raw", r, f) assert desc == "[cannot decode] Raw" + del r.headers["content-encoding"] + r.headers["content-type"] = "multipart/form-data; boundary=AaB03x" + r.content = b""" +--AaB03x +Content-Disposition: form-data; name="submit-name" + +Larry +--AaB03x + """.strip() + desc, lines, err = contentviews.get_message_content_view("multipart form", r, f) + assert desc == "Multipart form" + r.content = None desc, lines, err = contentviews.get_message_content_view("raw", r, f) assert list(lines) == [[("error", "content missing")]] diff --git a/test/mitmproxy/contentviews/test_auto.py b/test/mitmproxy/contentviews/test_auto.py index 6911eddf2b..63f41754da 100644 --- a/test/mitmproxy/contentviews/test_auto.py +++ b/test/mitmproxy/contentviews/test_auto.py @@ -46,7 +46,7 @@ def test_view_auto(): ) assert f[0] == "Unknown Image" - f = v(b"\xFF" * 30) + f = v(b"\xff" * 30) assert f[0] == "Hexdump" f = v( diff --git a/test/mitmproxy/contentviews/test_graphql.py b/test/mitmproxy/contentviews/test_graphql.py index 89beda814c..f10af244ff 100644 --- a/test/mitmproxy/contentviews/test_graphql.py +++ b/test/mitmproxy/contentviews/test_graphql.py @@ -19,6 +19,7 @@ def test_render_priority(): assert 0 == v.render_priority( b"""[{"xquery": "query P { \\n }"}]""", content_type="application/json" ) + assert 0 == v.render_priority(b"""[]""", content_type="application/json") assert 0 == v.render_priority(b"}", content_type="application/json") diff --git a/test/mitmproxy/contentviews/test_hex.py b/test/mitmproxy/contentviews/test_hex.py index 1e7f9ff9c2..201aa14275 100644 --- a/test/mitmproxy/contentviews/test_hex.py +++ b/test/mitmproxy/contentviews/test_hex.py @@ -10,7 +10,7 @@ def test_view_hex(self): def test_render_priority(self): v = hex.ViewHexDump() assert not v.render_priority(b"ascii") - assert v.render_priority(b"\xFF") + assert v.render_priority(b"\xff") assert not v.render_priority(b"") @@ -22,5 +22,5 @@ def test_view_hex(self): def test_render_priority(self): v = hex.ViewHexStream() assert not v.render_priority(b"ascii") - assert v.render_priority(b"\xFF") + assert v.render_priority(b"\xff") assert not v.render_priority(b"") diff --git a/test/mitmproxy/contentviews/test_json.py b/test/mitmproxy/contentviews/test_json.py index 9711a64659..abfbc461f4 100644 --- a/test/mitmproxy/contentviews/test_json.py +++ b/test/mitmproxy/contentviews/test_json.py @@ -12,7 +12,7 @@ def test_parse_json(): assert json.parse_json( b'{"foo" : "\xe4\xb8\x96\xe7\x95\x8c"}' ) # utf8 with chinese characters - assert json.parse_json(b'{"foo" : "\xFF"}') is json.PARSE_ERROR + assert json.parse_json(b'{"foo" : "\xff"}') is json.PARSE_ERROR def test_format_json(): @@ -78,6 +78,22 @@ def test_format_json(): [("text", " "), ("text", "]"), ("text", "")], [("text", ""), ("text", "}")], ] + assert list(json.format_json({"list": []})) == [ + [("text", "{"), ("text", "")], + [ + ("text", " "), + ("Token_Name_Tag", '"list"'), + ("text", ": "), + ("text", "[]"), + ("text", ""), + ], + [("text", ""), ("text", "}")], + ] + assert list(json.format_json(None)) == [[("Token_Keyword_Constant", "null")]] + assert list(json.format_json(True)) == [[("Token_Keyword_Constant", "true")]] + assert list(json.format_json(1)) == [[("Token_Literal_Number", "1")]] + assert list(json.format_json("test")) == [[("Token_Literal_String", '"test"')]] + assert list(json.format_json([])) == [[("text", "[]")]] def test_view_json(): @@ -88,6 +104,7 @@ def test_view_json(): assert v(b"[1, 2, 3, 4, 5]") assert v(b'{"foo" : 3}') assert v(b'{"foo": true, "nullvalue": null}') + assert v(b"[]") @given(binary()) diff --git a/test/mitmproxy/contentviews/test_mqtt.py b/test/mitmproxy/contentviews/test_mqtt.py index 87cc09d40e..9c966eb25a 100644 --- a/test/mitmproxy/contentviews/test_mqtt.py +++ b/test/mitmproxy/contentviews/test_mqtt.py @@ -7,13 +7,13 @@ @pytest.mark.parametrize( "data,expected_text", [ - pytest.param(b"\xC0\x00", "[PINGREQ]", id="PINGREQ"), - pytest.param(b"\xD0\x00", "[PINGRESP]", id="PINGRESP"), + pytest.param(b"\xc0\x00", "[PINGREQ]", id="PINGREQ"), + pytest.param(b"\xd0\x00", "[PINGRESP]", id="PINGRESP"), pytest.param( b"\x90\x00", "Packet type SUBACK is not supported yet!", id="SUBACK" ), pytest.param( - b"\xA0\x00", + b"\xa0\x00", "Packet type UNSUBSCRIBE is not supported yet!", id="UNSUBSCRIBE", ), @@ -58,7 +58,7 @@ def test_view_mqtt(data, expected_text): assert output == [[("text", expected_text)]] -@pytest.mark.parametrize("data", [b"\xC0\xFF\xFF\xFF\xFF"]) +@pytest.mark.parametrize("data", [b"\xc0\xff\xff\xff\xff"]) def test_mqtt_malformed(data): v = full_eval(mqtt.ViewMQTT()) with pytest.raises(Exception): diff --git a/test/mitmproxy/contentviews/test_multipart.py b/test/mitmproxy/contentviews/test_multipart.py index a748231d64..a9b43c5f87 100644 --- a/test/mitmproxy/contentviews/test_multipart.py +++ b/test/mitmproxy/contentviews/test_multipart.py @@ -1,5 +1,6 @@ from . import full_eval from mitmproxy.contentviews import multipart +from mitmproxy.test import tutils def test_view_multipart(): @@ -13,6 +14,14 @@ def test_view_multipart(): """.strip() assert view(v, content_type="multipart/form-data; boundary=AaB03x") + req = tutils.treq() + req.headers["content-type"] = "multipart/form-data; boundary=AaB03x" + req.content = v + + assert view( + v, content_type="multipart/form-data; boundary=AaB03x", http_message=req + ) + assert not view(v) assert not view(v, content_type="multipart/form-data") diff --git a/test/mitmproxy/contentviews/test_raw.py b/test/mitmproxy/contentviews/test_raw.py index f5020c2793..6e59e29052 100644 --- a/test/mitmproxy/contentviews/test_raw.py +++ b/test/mitmproxy/contentviews/test_raw.py @@ -11,9 +11,9 @@ def test_view_raw(): [[("text", "🫠".encode())]], ) # invalid utf8 - assert v(b"\xFF") == ( + assert v(b"\xff") == ( "Raw", - [[("text", b"\xFF")]], + [[("text", b"\xff")]], ) diff --git a/test/mitmproxy/contentviews/test_urlencoded.py b/test/mitmproxy/contentviews/test_urlencoded.py index e6005c0c8a..a91dab7366 100644 --- a/test/mitmproxy/contentviews/test_urlencoded.py +++ b/test/mitmproxy/contentviews/test_urlencoded.py @@ -12,7 +12,7 @@ def test_view_urlencoded(): d = url.encode([("adsfa", "")]).encode() assert v(d) - assert not v(b"\xFF\x00") + assert not v(b"\xff\x00") def test_render_priority(): diff --git a/test/mitmproxy/contentviews/test_wbxml.py b/test/mitmproxy/contentviews/test_wbxml.py index 11f2886bf8..d81a1c5439 100644 --- a/test/mitmproxy/contentviews/test_wbxml.py +++ b/test/mitmproxy/contentviews/test_wbxml.py @@ -7,7 +7,7 @@ def test_wbxml(tdata): v = full_eval(wbxml.ViewWBXML()) - assert v(b"\x03\x01\x6A\x00") == ("WBXML", [[("text", '')]]) + assert v(b"\x03\x01\x6a\x00") == ("WBXML", [[("text", '')]]) assert v(b"foo") is None path = tdata.path( diff --git a/test/mitmproxy/data/dumpfile-19.mitm b/test/mitmproxy/data/dumpfile-19.mitm new file mode 100644 index 0000000000..480dc10305 --- /dev/null +++ b/test/mitmproxy/data/dumpfile-19.mitm @@ -0,0 +1,2252 @@ +131541:9:websocket;0:~8:response;126314:6:reason;0:,11:status_code;3:200#13:timestamp_end;17:1726927927.799734^15:timestamp_start;18:1726927927.7027874^8:trailers;0:~7:content;125959: + + QUIC | Cloudflare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + +
+ +
+ + Industries + + + + +
+ + + + + + +
+ +
+ +
+ +
+ +
+
+ +
+ +
+ + Develop + + + + +
+ + + + + +
+ + Connect + + + + +
+ + +
+
+
+ + + + + +
+ +
+ + + + + +
+ + +
+
+
+
+
+

Does my browser support HTTP/3 & QUIC?

+ +

When loading this page from Cloudflare's edge network, your browser used HTTP/3.

+

This page is HTTP/3 & QUIC enabled. Try reloading a few times to spring it into action.

+

Not all HTTP clients have HTTP/3 & QUIC support configured. See our documentation for more information about how to check and configure your favorite client such as Chrome, Firefox or curl.

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

Available for all Cloudflare zones

+ +

Cloudflare's QUIC & HTTP/3 is generally available to all zones. You can control whether it is enabled or disabled using a toggle on the Network tab of your dashboard.

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

New to QUIC?

+ +

QUIC is a new transport protocol being developed in the Internet Engineering Task Force (IETF). It offers reliability, security and multiplexing by default.

+

HTTP/3 is a new version of HTTP that sits on top of QUIC. It leverages the new transport features to fix performance problems such as Head-of-Line blocking. This enables web pages to load faster, especially over troublesome networks.

+

If you’re new to QUIC and need to learn more about the protocol, the following resources will help you gain a better understanding.

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

Faster handshakes

+ +

QUIC handshakes are faster by design when compared to the equivalent TCP & TLS.

+

Since QUIC uses TLS 1.3, it can benefit from zero roundtrip time (0-RTT) connection resumption. Check out our 0-RTT blogpost to understand more about this feature.

+ +
+
+
+
+ +
+
+
+
+

Powered by delicious quiche

+ +

Quiche is Cloudflare's own open-source implementation of the QUIC and HTTP/3 protocols written in Rust.

+

The following articles provide some background.

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

Continuing developments

+ +

Cloudflare will continue to make updates to its QUIC implementation as the IETF makes progress towards finalizing the protocol standard.

+

Since launching QUIC & HTTP/3 support we've continued to measure performance and deploy optimisations such as new Congestion Control algorithms.

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

Get started

+ + + +
+
+
+
+ + + + +
+ +
+ +
+ + + +,7:headers;171:40:4:date,29:Sat, 21 Sep 2024 14:12:09 GMT,]28:12:content-type,9:text/html,]27:14:content-length,6:125959,]23:6:server,10:cloudflare,]33:6:cf-ray,20:8c6aa6058e1730db-FRA,]]12:http_version;6:HTTP/3,}7:request;318:4:path;1:/,9:authority;19:cloudflare-quic.com,6:scheme;5:https,6:method;3:GET,4:port;3:443#4:host;19:cloudflare-quic.com;13:timestamp_end;18:1726927927.6633708^15:timestamp_start;18:1726927927.6628444^8:trailers;0:~7:content;0:,7:headers;51:28:10:user-agent,10:curl/8.9.1,]15:6:accept,3:*/*,]]12:http_version;6:HTTP/3,}6:backup;0:~17:timestamp_created;18:1726927927.6629763^7:comment;0:;8:metadata;0:}6:marked;0:;9:is_replay;0:~11:intercepted;5:false!11:server_conn;4129:3:via;0:~19:timestamp_tcp_setup;0:~7:address;29:19:cloudflare-quic.com;3:443#]19:timestamp_tls_setup;17:1726927927.652231^13:timestamp_end;0:~15:timestamp_start;18:1726927927.5914717^3:sni;19:cloudflare-quic.com;11:tls_version;4:QUIC;11:cipher_list;0:]6:cipher;18:AES_256_GCM_SHA384;11:alpn_offers;5:2:h3,]4:alpn;2:h3,16:certificate_list;3610:1359:-----BEGIN CERTIFICATE----- +MIIDvTCCA2OgAwIBAgIQfhh2L/oNtKINNqCqBxC8uTAKBggqhkjOPQQDAjA7MQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMQwwCgYD +VQQDEwNXRTEwHhcNMjQwOTAzMDYwNzEyWhcNMjQxMjAyMDYwNzExWjAeMRwwGgYD +VQQDExNjbG91ZGZsYXJlLXF1aWMuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD +QgAEF2huuLoPM1zpmb7/VxTIoogVQlgutJM06dXnB8r7pvCmkAhuqyR/dkL/5cF8 +pxLW3OIVysPQQQpRwj1Lm6iC3KOCAmQwggJgMA4GA1UdDwEB/wQEAwIHgDATBgNV +HSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSh9T+DF7Tm +xFzZEpIqjbqdWYaKRjAfBgNVHSMEGDAWgBSQd5I1Z8T/qMyp5nvZgHl7zJP5ODBe +BggrBgEFBQcBAQRSMFAwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vLnBraS5nb29nL3Mv +d2UxL2ZoZzAlBggrBgEFBQcwAoYZaHR0cDovL2kucGtpLmdvb2cvd2UxLmNydDA1 +BgNVHREELjAsghNjbG91ZGZsYXJlLXF1aWMuY29tghUqLmNsb3VkZmxhcmUtcXVp +Yy5jb20wEwYDVR0gBAwwCjAIBgZngQwBAgEwNgYDVR0fBC8wLTAroCmgJ4YlaHR0 +cDovL2MucGtpLmdvb2cvd2UxL0pXVzNHajU2WmQ0LmNybDCCAQUGCisGAQQB1nkC +BAIEgfYEgfMA8QB2AHb/iD8KtvuVUcJhzPWHujS0pM27KdxoQgqf5mdMWjp0AAAB +kba1foQAAAQDAEcwRQIgHOTcOeZUJQc+kBVHwJHIqbvMnmx2D84nAFEfVv1x1EgC +IQDa0znSfzpHAIJ1/x8eWwUbgOK5e7Hn13R1DR057im4PgB3ANq2v2s/tbYin5vC +u1xr6HCRcWy7UYSFNL2kPTBI1/urAAABkba1fpEAAAQDAEgwRgIhAPjK86OWjZ/U +VrtJoGh2O00SgwW+4m13T1zuILLzYp0gAiEA075qC++r7e/KBafw69zsJ45JZF+i +N0LjWhF4WZ4yHYswCgYIKoZIzj0EAwIDSAAwRQIhALnaJ0FCYUhqQHSvCWgmBkXw +xqLr9zTDFVsHDm2jACBrAiAlovujZazaEb4n/GMSSL6BUM9VLeBZiUN0patcRTg2 +0A== +-----END CERTIFICATE----- +,969:-----BEGIN CERTIFICATE----- +MIICnzCCAiWgAwIBAgIQf/MZd5csIkp2FV0TttaF4zAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw +MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp +Y2VzMQwwCgYDVQQDEwNXRTEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARvzTr+ +Z1dHTCEDhUDCR127WEcPQMFcF4XGGTfn1XzthkubgdnXGhOlCgP4mMTG6J7/EFmP +LCaY9eYmJbsPAvpWo4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr +BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU +kHeSNWfE/6jMqeZ72YB5e8yT+TgwHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F +avCUHYwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku +Z29vZy9yNC5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv +ci9yNC5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDaAAwZQIx +AOcCq1HW90OVznX+0RGU1cxAQXomvtgM8zItPZCuFQ8jSBJSjz5keROv9aYsAm5V +sQIwJonMaAFi54mrfhfoFNZEfuNMSQ6/bIBiNLiyoX46FohQvKeIoJ99cx7sUkFN +7uJW +-----END CERTIFICATE----- +,1265:-----BEGIN CERTIFICATE----- +MIIDejCCAmKgAwIBAgIQf+UwvzMTQ77dghYQST2KGzANBgkqhkiG9w0BAQsFADBX +MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE +CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIzMTEx +NTAzNDMyMVoXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT +GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFI0 +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE83Rzp2iLYK5DuDXFgTB7S0md+8Fhzube +Rr1r1WEYNa5A3XP3iZEwWus87oV8okB2O6nGuEfYKueSkWpz6bFyOZ8pn6KY019e +WIZlD6GEZQbR3IvJx3PIjGov5cSr0R2Ko4H/MIH8MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUgEzW63T/STaj1dj8tT7FavCUHYwwHwYDVR0jBBgwFoAUYHtmGkUN +l8qJUC99BM00qP/8/UswNgYIKwYBBQUHAQEEKjAoMCYGCCsGAQUFBzAChhpodHRw +Oi8vaS5wa2kuZ29vZy9nc3IxLmNydDAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8v +Yy5wa2kuZ29vZy9yL2dzcjEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqG +SIb3DQEBCwUAA4IBAQAYQrsPBtYDh5bjP2OBDwmkoWhIDDkic574y04tfzHpn+cJ +odI2D4SseesQ6bDrarZ7C30ddLibZatoKiws3UL9xnELz4ct92vID24FfVbiI1hY ++SW6FoVHkNeWIP0GCbaM4C6uVdF5dTUsMVs/ZbzNnIdCp5Gxmx5ejvEau8otR/Cs +kGN+hr/W5GvT1tMBjgWKZ1i4//emhA1JG1BbPzoLJQvyEotc03lXjTaCzv8mEbep +8RqZ7a2CPsgRbuvTPBwcOMBBmuFeU88+FSBX6+7iP0il8b4Z0QFqIwwMHfs/L6K1 +vepuoxtGzi4CZ68zJpiq1UvSqTbFJjtbD4seiMHl +-----END CERTIFICATE----- +,]3:tls;4:true!5:error;0:~18:transport_protocol;3:udp;2:id;36:e47ee853-3b4f-4c26-9efe-2f0597c917ea;8:sockname;27:15:192.168.178.113;5:62652#]8:peername;21:11:104.22.8.38;3:443#]}11:client_conn;473:10:proxy_mode;36:reverse:https://cloudflare-quic.com/;8:mitmcert;0:~19:timestamp_tls_setup;18:1726927927.6583664^13:timestamp_end;0:~15:timestamp_start;17:1726927927.585847^3:sni;9:localhost;11:tls_version;4:QUIC;11:cipher_list;0:]6:cipher;18:AES_256_GCM_SHA384;11:alpn_offers;5:2:h3,]4:alpn;2:h3,16:certificate_list;0:]3:tls;4:true!5:error;0:~18:transport_protocol;3:udp;2:id;36:14d997f0-eb0b-4e39-958b-6ba688d9c705;8:sockname;12:2:::;4:8080#]8:peername;14:3:::1;5:62648#]}5:error;0:~2:id;36:82091aa1-7003-4aa6-9d00-d1e6ad69af03;4:type;4:http;7:version;2:20#} \ No newline at end of file diff --git a/test/mitmproxy/data/flows/error_log.har b/test/mitmproxy/data/flows/error_log.har index f41ee9575e..11e4c48796 100644 --- a/test/mitmproxy/data/flows/error_log.har +++ b/test/mitmproxy/data/flows/error_log.har @@ -61,8 +61,8 @@ }, "cache": {}, "timings": { - "connect": null, - "ssl": null, + "connect": -1.0, + "ssl": -1.0, "send": 2.851247787475586, "receive": 0, "wait": 0 @@ -169,4 +169,4 @@ } ] } -} \ No newline at end of file +} diff --git a/test/mitmproxy/data/flows/incomplete_log.har b/test/mitmproxy/data/flows/incomplete_log.har index 5b4c48fc6f..2d2c3709e3 100644 --- a/test/mitmproxy/data/flows/incomplete_log.har +++ b/test/mitmproxy/data/flows/incomplete_log.har @@ -45,8 +45,8 @@ }, "cache": {}, "timings": { - "connect": null, - "ssl": null, + "connect": -1.0, + "ssl": -1.0, "send": 0.0, "receive": 0, "wait": 0 @@ -89,8 +89,8 @@ }, "cache": {}, "timings": { - "connect": null, - "ssl": null, + "connect": -1.0, + "ssl": -1.0, "send": 0.00095367431640625, "receive": 0, "wait": 0 @@ -138,8 +138,8 @@ }, "cache": {}, "timings": { - "connect": null, - "ssl": null, + "connect": -1.0, + "ssl": -1.0, "send": 0.0, "receive": 0, "wait": 0 @@ -187,8 +187,8 @@ }, "cache": {}, "timings": { - "connect": null, - "ssl": null, + "connect": -1.0, + "ssl": -1.0, "send": 0.0, "receive": 0, "wait": 0 @@ -196,4 +196,4 @@ } ] } -} \ No newline at end of file +} diff --git a/test/mitmproxy/data/har_files/charles.json b/test/mitmproxy/data/har_files/charles.json index d38a849a9a..8077a35474 100644 --- a/test/mitmproxy/data/har_files/charles.json +++ b/test/mitmproxy/data/har_files/charles.json @@ -26,7 +26,7 @@ "tls_version": null, "timestamp_start": 1680136662.482, "timestamp_tls_setup": null, - "timestamp_end": 1680136769.482 + "timestamp_end": 1680136662.5890002 }, "server_conn": { "id": "hardcoded_for_test", @@ -71,7 +71,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680136662.482, - "timestamp_end": 1680136769.482, + "timestamp_end": 1680136662.5890002, "pretty_host": "mitmproxy.org" }, "response": { @@ -81,7 +81,7 @@ "headers": [ [ "Content-Type", - "text/html; charset=utf-8" + "text/html" ], [ "Content-Length", @@ -139,7 +139,7 @@ "contentLength": 23866, "contentHash": "7fd5f643a86976f5711df86ae2d5f9f8137a47c705dee31ccc550215564a5364", "timestamp_start": 1680136662.482, - "timestamp_end": 1680136769.482 + "timestamp_end": 1680136662.5890002 } } ] \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/chrome.json b/test/mitmproxy/data/har_files/chrome.json index d7fdc4035d..240c99c3ec 100644 --- a/test/mitmproxy/data/har_files/chrome.json +++ b/test/mitmproxy/data/har_files/chrome.json @@ -26,7 +26,7 @@ "tls_version": null, "timestamp_start": 1680134454.25, "timestamp_tls_setup": null, - "timestamp_end": 1680134468.9160001 + "timestamp_end": 1680134454.264666 }, "server_conn": { "id": "hardcoded_for_test", @@ -147,7 +147,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134454.25, - "timestamp_end": 1680134468.9160001, + "timestamp_end": 1680134454.264666, "pretty_host": "mitmproxy.org" }, "response": { @@ -194,16 +194,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "23866" ] ], "contentLength": 23866, "contentHash": "7fd5f643a86976f5711df86ae2d5f9f8137a47c705dee31ccc550215564a5364", "timestamp_start": 1680134454.25, - "timestamp_end": 1680134468.9160001 + "timestamp_end": 1680134454.264666 } }, { @@ -233,7 +229,7 @@ "tls_version": null, "timestamp_start": 1689251552.676, "timestamp_tls_setup": null, - "timestamp_end": 1689251556.795 + "timestamp_end": 1689251552.680119 }, "server_conn": { "id": "hardcoded_for_test", @@ -319,23 +315,18 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1689251552.676, - "timestamp_end": 1689251556.795, + "timestamp_end": 1689251552.680119, "pretty_host": "www.google.com" }, "response": { "http_version": "HTTP/1.1", "status_code": 0, "reason": "", - "headers": [ - [ - "content-length", - "0" - ] - ], + "headers": [], "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1689251552.676, - "timestamp_end": 1689251556.795 + "timestamp_end": 1689251552.680119 } }, { @@ -365,7 +356,7 @@ "tls_version": null, "timestamp_start": 1690289926.182, "timestamp_tls_setup": null, - "timestamp_end": 1690289984.3869998 + "timestamp_end": 1690289926.2402048 }, "server_conn": { "id": "hardcoded_for_test", @@ -510,7 +501,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1690289926.182, - "timestamp_end": 1690289984.3869998, + "timestamp_end": 1690289926.2402048, "pretty_host": "www.google.com" }, "response": { @@ -578,7 +569,7 @@ "contentLength": 7108, "contentHash": "d2c8a5c554b741fab4a622552e5f89d8a75b09baa3bc5b37819a4279217d6cec", "timestamp_start": 1690289926.182, - "timestamp_end": 1690289984.3869998 + "timestamp_end": 1690289926.2402048 } } ] \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/firefox.json b/test/mitmproxy/data/har_files/firefox.json index 849cb79edc..e3b701447f 100644 --- a/test/mitmproxy/data/har_files/firefox.json +++ b/test/mitmproxy/data/har_files/firefox.json @@ -26,7 +26,7 @@ "tls_version": null, "timestamp_start": 1680134339.303, "timestamp_tls_setup": null, - "timestamp_end": 1680134362.303 + "timestamp_end": 1680134339.326 }, "server_conn": { "id": "hardcoded_for_test", @@ -127,7 +127,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.303, - "timestamp_end": 1680134362.303, + "timestamp_end": 1680134339.326, "pretty_host": "mitmproxy.org" }, "response": { @@ -174,20 +174,12 @@ [ "x-amz-cf-id", "DPEkuUbeK1ZXMsRuUHqgk6iE4l7ShgyrJntkqIbLaSJ5646Ptc2Xew==" - ], - [ - "content-type", - "text/plain; charset=utf-8" - ], - [ - "content-length", - "23866" ] ], "contentLength": 23866, "contentHash": "7fd5f643a86976f5711df86ae2d5f9f8137a47c705dee31ccc550215564a5364", "timestamp_start": 1680134339.303, - "timestamp_end": 1680134362.303 + "timestamp_end": 1680134339.326 } }, { @@ -282,12 +274,7 @@ "http_version": "HTTP/1.1", "status_code": 200, "reason": "OK", - "headers": [ - [ - "content-length", - "0" - ] - ], + "headers": [], "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.418, @@ -386,12 +373,7 @@ "http_version": "HTTP/1.1", "status_code": 200, "reason": "OK", - "headers": [ - [ - "content-length", - "0" - ] - ], + "headers": [], "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.456, @@ -490,12 +472,7 @@ "http_version": "HTTP/1.1", "status_code": 200, "reason": "OK", - "headers": [ - [ - "content-length", - "0" - ] - ], + "headers": [], "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.457, @@ -594,12 +571,7 @@ "http_version": "HTTP/1.1", "status_code": 200, "reason": "OK", - "headers": [ - [ - "content-length", - "0" - ] - ], + "headers": [], "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.457, @@ -698,12 +670,7 @@ "http_version": "HTTP/1.1", "status_code": 200, "reason": "OK", - "headers": [ - [ - "content-length", - "0" - ] - ], + "headers": [], "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.458, @@ -878,10 +845,6 @@ [ "x-amz-cf-id", "EufbwzXQheESUTNil_OCjKK8cvVL51cQpYfmF7iZSHloCTvVhfZ8yQ==" - ], - [ - "content-length", - "3969" ] ], "contentLength": 3969, @@ -1058,10 +1021,6 @@ [ "x-amz-cf-id", "UuHHTyGhTqqTO07G_oZCw7rxjb9RJUGTN3OW0EUS77RH4GiQ-LkAvw==" - ], - [ - "content-length", - "3346" ] ], "contentLength": 3346, @@ -1238,10 +1197,6 @@ [ "x-amz-cf-id", "TOLqHpQWMFHQDWnv2yHHFWI5xkA3R13TTJQDJe1ARViKrgihxZdhxA==" - ], - [ - "content-length", - "794" ] ], "contentLength": 794, @@ -1277,7 +1232,7 @@ "tls_version": null, "timestamp_start": 1680134339.527, "timestamp_tls_setup": null, - "timestamp_end": 1680134345.527 + "timestamp_end": 1680134339.533 }, "server_conn": { "id": "hardcoded_for_test", @@ -1378,7 +1333,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.527, - "timestamp_end": 1680134345.527, + "timestamp_end": 1680134339.533, "pretty_host": "mitmproxy.org" }, "response": { @@ -1425,16 +1380,12 @@ [ "x-amz-cf-id", "nnIrWtgAMt42ua4HYBtNAao6m_iD9WjIzLAFyURb8mjOr5MriSQXRA==" - ], - [ - "content-length", - "9689" ] ], "contentLength": 9689, "contentHash": "a4dcfad01ab92fbd09cad3477fb26184fbb26f164d1302ee79489519b280e22a", "timestamp_start": 1680134339.527, - "timestamp_end": 1680134345.527 + "timestamp_end": 1680134339.533 } }, { @@ -1464,7 +1415,7 @@ "tls_version": null, "timestamp_start": 1680134339.528, "timestamp_tls_setup": null, - "timestamp_end": 1680134346.528 + "timestamp_end": 1680134339.535 }, "server_conn": { "id": "hardcoded_for_test", @@ -1565,7 +1516,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.528, - "timestamp_end": 1680134346.528, + "timestamp_end": 1680134339.535, "pretty_host": "mitmproxy.org" }, "response": { @@ -1612,16 +1563,12 @@ [ "x-amz-cf-id", "PMTLvP_yUCVocnhd1i1ir7_FRAJRw0ayMhK3KaZKELDO3pxxoqLWjg==" - ], - [ - "content-length", - "9689" ] ], "contentLength": 9689, "contentHash": "a4dcfad01ab92fbd09cad3477fb26184fbb26f164d1302ee79489519b280e22a", "timestamp_start": 1680134339.528, - "timestamp_end": 1680134346.528 + "timestamp_end": 1680134339.535 } }, { @@ -1651,7 +1598,7 @@ "tls_version": null, "timestamp_start": 1680134339.543, "timestamp_tls_setup": null, - "timestamp_end": 1680134586.543 + "timestamp_end": 1680134339.79 }, "server_conn": { "id": "hardcoded_for_test", @@ -1736,7 +1683,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.543, - "timestamp_end": 1680134586.543, + "timestamp_end": 1680134339.79, "pretty_host": "s3-us-west-2.amazonaws.com" }, "response": { @@ -1792,7 +1739,7 @@ "contentLength": 3406, "contentHash": "1463cf2c4e430b2373b9cd16548f263d3335bc245fdca8019d56a4c9e6ae3b14", "timestamp_start": 1680134339.543, - "timestamp_end": 1680134586.543 + "timestamp_end": 1680134339.79 } }, { @@ -1822,7 +1769,7 @@ "tls_version": null, "timestamp_start": 1680134339.639, "timestamp_tls_setup": null, - "timestamp_end": 1680134346.639 + "timestamp_end": 1680134339.646 }, "server_conn": { "id": "hardcoded_for_test", @@ -1911,7 +1858,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680134339.639, - "timestamp_end": 1680134346.639, + "timestamp_end": 1680134339.646, "pretty_host": "mitmproxy.org" }, "response": { @@ -1958,16 +1905,12 @@ [ "x-amz-cf-id", "0okGWJw6nYo7R-4egQWE-WfonThN2EXyRSLO9MlCNKyMfD-2v1AU0Q==" - ], - [ - "content-length", - "6986" ] ], "contentLength": 6986, "contentHash": "ebb5ca702c6b7f09fe1c10e8992602bad67989e25151f0cb6928ea51299bf4e8", "timestamp_start": 1680134339.639, - "timestamp_end": 1680134346.639 + "timestamp_end": 1680134339.646 } }, { diff --git a/test/mitmproxy/data/har_files/head-content-length.har b/test/mitmproxy/data/har_files/head-content-length.har new file mode 100644 index 0000000000..ec549cbe9d --- /dev/null +++ b/test/mitmproxy/data/har_files/head-content-length.har @@ -0,0 +1,179 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Firefox", + "version": "111.0.1" + }, + "browser": { + "name": "Firefox", + "version": "111.0.1" + }, + "pages": [ + { + "startedDateTime": "2023-03-29T16:58:59.303-07:00", + "id": "page_1", + "title": "mitmproxy - an interactive HTTPS proxy", + "pageTimings": { + "onContentLoad": 208, + "onLoad": 270 + } + } + ], + "entries": [ + { + "startedDateTime": "2023-12-12T16:23:16.067544+00:00", + "time": 101.56393051147461, + "request": { + "method": "HEAD", + "url": "https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl", + "httpVersion": "HTTP/2.0", + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "*/*" + }, + { + "name": "user-agent", + "value": "puffin" + }, + { + "name": "accept-encoding", + "value": "gzip, br" + } + ], + "queryString": [], + "headersSize": 91, + "bodySize": 0 + }, + "response": { + "status": 200, + "statusText": "", + "httpVersion": "HTTP/2.0", + "cookies": [], + "headers": [ + { + "name": "last-modified", + "value": "Thu, 10 Aug 2023 11:39:00 GMT" + }, + { + "name": "etag", + "value": "\"a296c6e224c118b0d08cd77e8c08f4b1\"" + }, + { + "name": "x-amz-request-id", + "value": "aeb4d3335548af85" + }, + { + "name": "x-amz-id-2", + "value": "aN65jxTFgNrlm8zEJMNdk7mYLYwUwTzh0" + }, + { + "name": "x-amz-version-id", + "value": "4_z179c51e67f11a0ad8f6c0018_f10789ff3151435c8_d20230810_m113900_c005_v0501001_t0045_u01691667540984" + }, + { + "name": "content-type", + "value": "application/octet-stream" + }, + { + "name": "cache-control", + "value": "max-age=365000000, immutable, public" + }, + { + "name": "accept-ranges", + "value": "bytes" + }, + { + "name": "date", + "value": "Tue, 12 Dec 2023 16:23:16 GMT" + }, + { + "name": "age", + "value": "2335275" + }, + { + "name": "x-served-by", + "value": "cache-iad-kcgs7200038-IAD, cache-lck10926-LCK" + }, + { + "name": "x-cache", + "value": "HIT, HIT" + }, + { + "name": "x-cache-hits", + "value": "21459, 139679" + }, + { + "name": "x-timer", + "value": "S1702398196.107663,VS0,VE0" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload" + }, + { + "name": "x-frame-options", + "value": "deny" + }, + { + "name": "x-xss-protection", + "value": "1; mode=block" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-permitted-cross-domain-policies", + "value": "none" + }, + { + "name": "x-robots-header", + "value": "noindex" + }, + { + "name": "x-pypi-file-python-version", + "value": "py3" + }, + { + "name": "x-pypi-file-version", + "value": "4.66.1" + }, + { + "name": "x-pypi-file-package-type", + "value": "bdist_wheel" + }, + { + "name": "x-pypi-file-project", + "value": "tqdm" + }, + { + "name": "content-length", + "value": "78258" + } + ], + "content": { + "size": 0, + "compression": 0, + "mimeType": "application/octet-stream", + "text": "" + }, + "redirectURL": "", + "headersSize": 1188, + "bodySize": 0 + }, + "cache": {}, + "timings": { + "connect": 31.686782836914062, + "ssl": 35.33315658569336, + "send": 0.2961158752441406, + "receive": 0.6310939788818359, + "wait": 33.61678123474121 + }, + "serverIPAddress": "199.232.96.223" + } + ] + } +} \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/head-content-length.json b/test/mitmproxy/data/har_files/head-content-length.json new file mode 100644 index 0000000000..a3248bb4e9 --- /dev/null +++ b/test/mitmproxy/data/har_files/head-content-length.json @@ -0,0 +1,193 @@ +[ + { + "id": "hardcoded_for_test", + "intercepted": false, + "is_replay": null, + "type": "http", + "modified": false, + "marked": "", + "comment": "", + "timestamp_created": 0, + "client_conn": { + "id": "hardcoded_for_test", + "peername": [ + "127.0.0.1", + 0 + ], + "sockname": [ + "127.0.0.1", + 0 + ], + "tls_established": false, + "cert": null, + "sni": null, + "cipher": null, + "alpn": null, + "tls_version": null, + "timestamp_start": 1702398196.067544, + "timestamp_tls_setup": null, + "timestamp_end": 1702398196.169108 + }, + "server_conn": { + "id": "hardcoded_for_test", + "peername": null, + "sockname": null, + "address": [ + "199.232.96.223", + 443 + ], + "tls_established": false, + "cert": null, + "sni": null, + "cipher": null, + "alpn": null, + "tls_version": null, + "timestamp_start": null, + "timestamp_tcp_setup": null, + "timestamp_tls_setup": null, + "timestamp_end": null + }, + "request": { + "method": "HEAD", + "scheme": "https", + "host": "files.pythonhosted.org", + "port": 443, + "path": "/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl", + "http_version": "HTTP/1.1", + "headers": [ + [ + "accept", + "*/*" + ], + [ + "user-agent", + "puffin" + ], + [ + "accept-encoding", + "gzip, br" + ], + [ + "content-length", + "0" + ] + ], + "contentLength": 0, + "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "timestamp_start": 1702398196.067544, + "timestamp_end": 1702398196.169108, + "pretty_host": "files.pythonhosted.org" + }, + "response": { + "http_version": "HTTP/1.1", + "status_code": 200, + "reason": "OK", + "headers": [ + [ + "last-modified", + "Thu, 10 Aug 2023 11:39:00 GMT" + ], + [ + "etag", + "\"a296c6e224c118b0d08cd77e8c08f4b1\"" + ], + [ + "x-amz-request-id", + "aeb4d3335548af85" + ], + [ + "x-amz-id-2", + "aN65jxTFgNrlm8zEJMNdk7mYLYwUwTzh0" + ], + [ + "x-amz-version-id", + "4_z179c51e67f11a0ad8f6c0018_f10789ff3151435c8_d20230810_m113900_c005_v0501001_t0045_u01691667540984" + ], + [ + "content-type", + "application/octet-stream" + ], + [ + "cache-control", + "max-age=365000000, immutable, public" + ], + [ + "accept-ranges", + "bytes" + ], + [ + "date", + "Tue, 12 Dec 2023 16:23:16 GMT" + ], + [ + "age", + "2335275" + ], + [ + "x-served-by", + "cache-iad-kcgs7200038-IAD, cache-lck10926-LCK" + ], + [ + "x-cache", + "HIT, HIT" + ], + [ + "x-cache-hits", + "21459, 139679" + ], + [ + "x-timer", + "S1702398196.107663,VS0,VE0" + ], + [ + "strict-transport-security", + "max-age=31536000; includeSubDomains; preload" + ], + [ + "x-frame-options", + "deny" + ], + [ + "x-xss-protection", + "1; mode=block" + ], + [ + "x-content-type-options", + "nosniff" + ], + [ + "x-permitted-cross-domain-policies", + "none" + ], + [ + "x-robots-header", + "noindex" + ], + [ + "x-pypi-file-python-version", + "py3" + ], + [ + "x-pypi-file-version", + "4.66.1" + ], + [ + "x-pypi-file-package-type", + "bdist_wheel" + ], + [ + "x-pypi-file-project", + "tqdm" + ], + [ + "content-length", + "78258" + ] + ], + "contentLength": 0, + "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "timestamp_start": 1702398196.067544, + "timestamp_end": 1702398196.169108 + } + } +] \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/insomnia.json b/test/mitmproxy/data/har_files/insomnia.json index d2f39b93f6..62630b0003 100644 --- a/test/mitmproxy/data/har_files/insomnia.json +++ b/test/mitmproxy/data/har_files/insomnia.json @@ -26,7 +26,7 @@ "tls_version": null, "timestamp_start": 1680151158.981, "timestamp_tls_setup": null, - "timestamp_end": 1680151229.383 + "timestamp_end": 1680151159.0514019 }, "server_conn": { "id": "hardcoded_for_test", @@ -60,7 +60,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680151158.981, - "timestamp_end": 1680151229.383, + "timestamp_end": 1680151159.0514019, "pretty_host": "mitm.it" }, "response": { @@ -132,7 +132,7 @@ "contentLength": 250, "contentHash": "ad5724ee351ebc53212702f448c0136f3892e52036fb9e5918192a130bde38bd", "timestamp_start": 1680151158.981, - "timestamp_end": 1680151229.383 + "timestamp_end": 1680151159.0514019 } } ] \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/postdata.json b/test/mitmproxy/data/har_files/postdata.json index 0529a2438e..08c8b8abbf 100644 --- a/test/mitmproxy/data/har_files/postdata.json +++ b/test/mitmproxy/data/har_files/postdata.json @@ -26,7 +26,7 @@ "tls_version": null, "timestamp_start": 1689428246.093, "timestamp_tls_setup": null, - "timestamp_end": 1689428415.889 + "timestamp_end": 1689428246.262796 }, "server_conn": { "id": "hardcoded_for_test", @@ -139,7 +139,7 @@ "contentLength": 1310, "contentHash": "94c0d23b4e9f828b4b9062885ba0b785ce53fc374aef106b01fa62ff9f15c35b", "timestamp_start": 1689428246.093, - "timestamp_end": 1689428415.889, + "timestamp_end": 1689428246.262796, "pretty_host": "signal-metrics-collector-beta.s-onetag.com" }, "response": { @@ -167,7 +167,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1689428246.093, - "timestamp_end": 1689428415.889 + "timestamp_end": 1689428246.262796 } } ] \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/safari.json b/test/mitmproxy/data/har_files/safari.json index f1a9b01898..32ff04fff3 100644 --- a/test/mitmproxy/data/har_files/safari.json +++ b/test/mitmproxy/data/har_files/safari.json @@ -26,7 +26,7 @@ "tls_version": null, "timestamp_start": 1680135212.418, "timestamp_tls_setup": null, - "timestamp_end": 1680135323.7605977 + "timestamp_end": 1680135212.5293427 }, "server_conn": { "id": "hardcoded_for_test", @@ -91,7 +91,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.418, - "timestamp_end": 1680135323.7605977, + "timestamp_end": 1680135212.5293427, "pretty_host": "mitmproxy.org" }, "response": { @@ -101,7 +101,7 @@ "headers": [ [ "Content-Type", - "text/html; charset=utf-8" + "text/html" ], [ "Last-Modified", @@ -150,16 +150,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "4946" ] ], "contentLength": 4946, "contentHash": "b643b55c326524222b66cf8d6676c9b640e6417d23aaaa12c8a4ac58216d6586", "timestamp_start": 1680135212.418, - "timestamp_end": 1680135323.7605977 + "timestamp_end": 1680135212.5293427 } }, { @@ -189,7 +185,7 @@ "tls_version": null, "timestamp_start": 1680135212.542, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.606069 + "timestamp_end": 1680135212.5420642 }, "server_conn": { "id": "hardcoded_for_test", @@ -223,7 +219,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.542, - "timestamp_end": 1680135212.606069, + "timestamp_end": 1680135212.5420642, "pretty_host": "mitmproxy.org" }, "response": { @@ -282,16 +278,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "36819" ] ], "contentLength": 36819, "contentHash": "62c365a16e642d4b512700140d3e99371aed31b74edc736f9927b6375b1230c0", "timestamp_start": 1680135212.542, - "timestamp_end": 1680135212.606069 + "timestamp_end": 1680135212.5420642 } }, { @@ -321,7 +313,7 @@ "tls_version": null, "timestamp_start": 1680135212.552, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.625603 + "timestamp_end": 1680135212.5520737 }, "server_conn": { "id": "hardcoded_for_test", @@ -355,7 +347,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.552, - "timestamp_end": 1680135212.625603, + "timestamp_end": 1680135212.5520737, "pretty_host": "mitmproxy.org" }, "response": { @@ -419,7 +411,7 @@ "contentLength": 2145, "contentHash": "4947ce36b175decddf46297b9bdce05c6bea88aec0547117c2a2483c202bb603", "timestamp_start": 1680135212.552, - "timestamp_end": 1680135212.625603 + "timestamp_end": 1680135212.5520737 } }, { @@ -449,7 +441,7 @@ "tls_version": null, "timestamp_start": 1680135212.554, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.604729 + "timestamp_end": 1680135212.5540507 }, "server_conn": { "id": "hardcoded_for_test", @@ -483,7 +475,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.554, - "timestamp_end": 1680135212.604729, + "timestamp_end": 1680135212.5540507, "pretty_host": "mitmproxy.org" }, "response": { @@ -547,7 +539,7 @@ "contentLength": 117218, "contentHash": "46b65528ed54e9077594c932b754a3a2f82059c7febc672d3279b87ec672d9b7", "timestamp_start": 1680135212.554, - "timestamp_end": 1680135212.604729 + "timestamp_end": 1680135212.5540507 } }, { @@ -577,7 +569,7 @@ "tls_version": null, "timestamp_start": 1680135212.555, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.609786 + "timestamp_end": 1680135212.555055 }, "server_conn": { "id": "hardcoded_for_test", @@ -611,7 +603,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.555, - "timestamp_end": 1680135212.609786, + "timestamp_end": 1680135212.555055, "pretty_host": "mitmproxy.org" }, "response": { @@ -675,7 +667,7 @@ "contentLength": 26548, "contentHash": "909ddb806a674602080bb5d8311cf6fd54362b939ca35d2152f80e88c5093b83", "timestamp_start": 1680135212.555, - "timestamp_end": 1680135212.609786 + "timestamp_end": 1680135212.555055 } }, { @@ -705,7 +697,7 @@ "tls_version": null, "timestamp_start": 1680135212.555, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.856044 + "timestamp_end": 1680135212.5553012 }, "server_conn": { "id": "hardcoded_for_test", @@ -739,7 +731,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.555, - "timestamp_end": 1680135212.856044, + "timestamp_end": 1680135212.5553012, "pretty_host": "mitmproxy.org" }, "response": { @@ -803,7 +795,7 @@ "contentLength": 10780, "contentHash": "7daa40f6d8bd5c5d6cb7adc350378695cb6c7e2ea6b58a1a2c4460a9f427a6ca", "timestamp_start": 1680135212.555, - "timestamp_end": 1680135212.856044 + "timestamp_end": 1680135212.5553012 } }, { @@ -833,7 +825,7 @@ "tls_version": null, "timestamp_start": 1680135212.557, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.8695679 + "timestamp_end": 1680135212.5573125 }, "server_conn": { "id": "hardcoded_for_test", @@ -867,7 +859,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.557, - "timestamp_end": 1680135212.8695679, + "timestamp_end": 1680135212.5573125, "pretty_host": "mitmproxy.org" }, "response": { @@ -926,16 +918,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "5167" ] ], "contentLength": 5167, "contentHash": "8a74d8c765558a54c3fb4eeb2e24367cfca6a889f0d56b7fc179eb722e5f8ebf", "timestamp_start": 1680135212.557, - "timestamp_end": 1680135212.8695679 + "timestamp_end": 1680135212.5573125 } }, { @@ -965,7 +953,7 @@ "tls_version": null, "timestamp_start": 1680135212.559, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.631427 + "timestamp_end": 1680135212.5590725 }, "server_conn": { "id": "hardcoded_for_test", @@ -999,7 +987,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.559, - "timestamp_end": 1680135212.631427, + "timestamp_end": 1680135212.5590725, "pretty_host": "mitmproxy.org" }, "response": { @@ -1058,16 +1046,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "3346" ] ], "contentLength": 3346, "contentHash": "e6c21f88023539515a971172a00e500b7e4444fbf9506e47ceee126ace246808", "timestamp_start": 1680135212.559, - "timestamp_end": 1680135212.631427 + "timestamp_end": 1680135212.5590725 } }, { @@ -1097,7 +1081,7 @@ "tls_version": null, "timestamp_start": 1680135212.559, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.620405 + "timestamp_end": 1680135212.5590615 }, "server_conn": { "id": "hardcoded_for_test", @@ -1131,7 +1115,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.559, - "timestamp_end": 1680135212.620405, + "timestamp_end": 1680135212.5590615, "pretty_host": "mitmproxy.org" }, "response": { @@ -1190,16 +1174,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "794" ] ], "contentLength": 794, "contentHash": "43cb84ef784bafbab5472abc7c396d95fc4468973d6501c83709e40963b2a953", "timestamp_start": 1680135212.559, - "timestamp_end": 1680135212.620405 + "timestamp_end": 1680135212.5590615 } }, { @@ -1229,7 +1209,7 @@ "tls_version": null, "timestamp_start": 1680135212.56, "timestamp_tls_setup": null, - "timestamp_end": 1680135247.3946638 + "timestamp_end": 1680135212.5948346 }, "server_conn": { "id": "hardcoded_for_test", @@ -1275,7 +1255,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135247.3946638, + "timestamp_end": 1680135212.5948346, "pretty_host": "mitmproxy.org" }, "response": { @@ -1334,16 +1314,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "3346" ] ], "contentLength": 3346, "contentHash": "1f3ac146af1c45c1a2b4e6c694ecb234382d77b4256524d5ffc365fc8d6130b0", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135247.3946638 + "timestamp_end": 1680135212.5948346 } }, { @@ -1373,7 +1349,7 @@ "tls_version": null, "timestamp_start": 1680135212.56, "timestamp_tls_setup": null, - "timestamp_end": 1680135247.3946638 + "timestamp_end": 1680135212.5948346 }, "server_conn": { "id": "hardcoded_for_test", @@ -1419,7 +1395,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135247.3946638, + "timestamp_end": 1680135212.5948346, "pretty_host": "mitmproxy.org" }, "response": { @@ -1478,16 +1454,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "3346" ] ], "contentLength": 3346, "contentHash": "1f3ac146af1c45c1a2b4e6c694ecb234382d77b4256524d5ffc365fc8d6130b0", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135247.3946638 + "timestamp_end": 1680135212.5948346 } }, { @@ -1517,7 +1489,7 @@ "tls_version": null, "timestamp_start": 1680135212.56, "timestamp_tls_setup": null, - "timestamp_end": 1680135252.528817 + "timestamp_end": 1680135212.5999687 }, "server_conn": { "id": "hardcoded_for_test", @@ -1563,7 +1535,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135252.528817, + "timestamp_end": 1680135212.5999687, "pretty_host": "mitmproxy.org" }, "response": { @@ -1622,16 +1594,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "3346" ] ], "contentLength": 3346, "contentHash": "1f3ac146af1c45c1a2b4e6c694ecb234382d77b4256524d5ffc365fc8d6130b0", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135252.528817 + "timestamp_end": 1680135212.5999687 } }, { @@ -1661,7 +1629,7 @@ "tls_version": null, "timestamp_start": 1680135212.56, "timestamp_tls_setup": null, - "timestamp_end": 1680135252.528817 + "timestamp_end": 1680135212.5999687 }, "server_conn": { "id": "hardcoded_for_test", @@ -1707,7 +1675,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135252.528817, + "timestamp_end": 1680135212.5999687, "pretty_host": "mitmproxy.org" }, "response": { @@ -1766,16 +1734,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "3346" ] ], "contentLength": 3346, "contentHash": "1f3ac146af1c45c1a2b4e6c694ecb234382d77b4256524d5ffc365fc8d6130b0", "timestamp_start": 1680135212.56, - "timestamp_end": 1680135252.528817 + "timestamp_end": 1680135212.5999687 } }, { @@ -1805,7 +1769,7 @@ "tls_version": null, "timestamp_start": 1680135212.564, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.644795 + "timestamp_end": 1680135212.5640807 }, "server_conn": { "id": "hardcoded_for_test", @@ -1839,7 +1803,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.564, - "timestamp_end": 1680135212.644795, + "timestamp_end": 1680135212.5640807, "pretty_host": "mitmproxy.org" }, "response": { @@ -1903,7 +1867,7 @@ "contentLength": 76736, "contentHash": "8ea8791754915a898a3100e63e32978a6d1763be6df8e73a39d3a90d691cdeef", "timestamp_start": 1680135212.564, - "timestamp_end": 1680135212.644795 + "timestamp_end": 1680135212.5640807 } }, { @@ -1933,7 +1897,7 @@ "tls_version": null, "timestamp_start": 1680135212.565, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.609024 + "timestamp_end": 1680135212.5650442 }, "server_conn": { "id": "hardcoded_for_test", @@ -1967,7 +1931,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.565, - "timestamp_end": 1680135212.609024, + "timestamp_end": 1680135212.5650442, "pretty_host": "mitmproxy.org" }, "response": { @@ -2031,7 +1995,7 @@ "contentLength": 13224, "contentHash": "e42a88444448ac3d60549cc7c1ff2c8a9cac721034c073d80a14a44e79730cca", "timestamp_start": 1680135212.565, - "timestamp_end": 1680135212.609024 + "timestamp_end": 1680135212.5650442 } }, { @@ -2061,7 +2025,7 @@ "tls_version": null, "timestamp_start": 1680135212.565, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.622383 + "timestamp_end": 1680135212.5650575 }, "server_conn": { "id": "hardcoded_for_test", @@ -2095,7 +2059,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.565, - "timestamp_end": 1680135212.622383, + "timestamp_end": 1680135212.5650575, "pretty_host": "mitmproxy.org" }, "response": { @@ -2159,7 +2123,7 @@ "contentLength": 78268, "contentHash": "9834b82ad26e2a37583d22676a12dd2eb0fe7c80356a2114d0db1aa8b3899537", "timestamp_start": 1680135212.565, - "timestamp_end": 1680135212.622383 + "timestamp_end": 1680135212.5650575 } }, { @@ -2189,7 +2153,7 @@ "tls_version": null, "timestamp_start": 1680135212.583, "timestamp_tls_setup": null, - "timestamp_end": 1680135212.729846 + "timestamp_end": 1680135212.5831468 }, "server_conn": { "id": "hardcoded_for_test", @@ -2223,7 +2187,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.583, - "timestamp_end": 1680135212.729846, + "timestamp_end": 1680135212.5831468, "pretty_host": "mitmproxy.org" }, "response": { @@ -2282,16 +2246,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "3969" ] ], "contentLength": 3969, "contentHash": "3c4880b4b424071aa5e5c5f652b934179099ee8786ea67520b2fadbc4305e5a8", "timestamp_start": 1680135212.583, - "timestamp_end": 1680135212.729846 + "timestamp_end": 1680135212.5831468 } }, { @@ -2321,7 +2281,7 @@ "tls_version": null, "timestamp_start": 1680135212.588, "timestamp_tls_setup": null, - "timestamp_end": 1680135389.811421 + "timestamp_end": 1680135212.7652235 }, "server_conn": { "id": "hardcoded_for_test", @@ -2390,7 +2350,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.588, - "timestamp_end": 1680135389.811421, + "timestamp_end": 1680135212.7652235, "pretty_host": "s3-us-west-2.amazonaws.com" }, "response": { @@ -2446,7 +2406,7 @@ "contentLength": 3406, "contentHash": "1463cf2c4e430b2373b9cd16548f263d3335bc245fdca8019d56a4c9e6ae3b14", "timestamp_start": 1680135212.588, - "timestamp_end": 1680135389.811421 + "timestamp_end": 1680135212.7652235 } }, { @@ -2476,7 +2436,7 @@ "tls_version": null, "timestamp_start": 1680135212.6, "timestamp_tls_setup": null, - "timestamp_end": 1680135222.496895 + "timestamp_end": 1680135212.609897 }, "server_conn": { "id": "hardcoded_for_test", @@ -2537,7 +2497,7 @@ "contentLength": 0, "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "timestamp_start": 1680135212.6, - "timestamp_end": 1680135222.496895, + "timestamp_end": 1680135212.609897, "pretty_host": "mitmproxy.org" }, "response": { @@ -2596,16 +2556,12 @@ [ "x-cache", "Hit from cloudfront" - ], - [ - "content-length", - "1421" ] ], "contentLength": 1421, "contentHash": "81de6d4a4bdb984627d61de60369ec4f0ce182170fbe6d9a980b15574d5f6c50", "timestamp_start": 1680135212.6, - "timestamp_end": 1680135222.496895 + "timestamp_end": 1680135212.609897 } } ] \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/with-bom.har b/test/mitmproxy/data/har_files/with-bom.har new file mode 100644 index 0000000000..1e790e2ebc --- /dev/null +++ b/test/mitmproxy/data/har_files/with-bom.har @@ -0,0 +1,189 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "WebInspector", + "version": "537.36" + }, + "pages": [], + "entries": [ + { + "_initiator": { + "type": "script", + "stack": { + "callFrames": [ + { + "functionName": "send", + "scriptId": "108", + "url": "https://signal-beacon.s-onetag.com/beacon.min.js", + "lineNumber": 21, + "columnNumber": 529 + }, + { + "functionName": "X", + "scriptId": "108", + "url": "https://signal-beacon.s-onetag.com/beacon.min.js", + "lineNumber": 33, + "columnNumber": 422 + }, + { + "functionName": "", + "scriptId": "108", + "url": "https://signal-beacon.s-onetag.com/beacon.min.js", + "lineNumber": 34, + "columnNumber": 343 + } + ] + } + }, + "_priority": "VeryLow", + "_resourceType": "ping", + "cache": {}, + "connection": "159834", + "request": { + "method": "POST", + "url": "https://signal-metrics-collector-beta.s-onetag.com/metrics", + "httpVersion": "http/2.0", + "headers": [ + { + "name": ":authority", + "value": "signal-metrics-collector-beta.s-onetag.com" + }, + { + "name": ":method", + "value": "POST" + }, + { + "name": ":path", + "value": "/metrics" + }, + { + "name": ":scheme", + "value": "https" + }, + { + "name": "accept", + "value": "*/*" + }, + { + "name": "accept-encoding", + "value": "gzip, deflate, br" + }, + { + "name": "accept-language", + "value": "en-US,en;q=0.9" + }, + { + "name": "cache-control", + "value": "no-cache" + }, + { + "name": "content-length", + "value": "1310" + }, + { + "name": "content-type", + "value": "text/plain;charset=UTF-8" + }, + { + "name": "dnt", + "value": "1" + }, + { + "name": "origin", + "value": "https://reqbin.com" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "sec-ch-ua", + "value": "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"" + }, + { + "name": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "name": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "name": "sec-fetch-dest", + "value": "empty" + }, + { + "name": "sec-fetch-mode", + "value": "no-cors" + }, + { + "name": "sec-fetch-site", + "value": "cross-site" + }, + { + "name": "user-agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" + } + ], + "queryString": [], + "cookies": [], + "headersSize": -1, + "bodySize": 1310, + "postData": { + "mimeType": "text/plain;charset=UTF-8", + "text": "{\"metadata\":{\"pageViewId\":1689428126308,\"affiliateId\":62299,\"domain\":\"reqbin.com\",\"path\":\"/post-online\",\"isCollectable\":true,\"consentString\":\"\",\"gppString\":\"\",\"location\":\"AT\",\"ljtReader\":\"\",\"query\":\"\",\"referrer\":\"https://www.google.com/\",\"canCollectIp\":false},\"payloads\":[{\"scrollDepth\":856,\"dwellTime\":76,\"engagedDwellTime\":5,\"documentHeight\":2958,\"type\":\"page\",\"userEids\":[]},{\"impressionId\":1689428184383,\"zoneId\":null,\"transactionId\":null,\"secondsInView\":0,\"gamAdUnitPath\":\"/1254144,21910826702/reqbin_com-box-4\",\"clicks\":0,\"viewableEngagedSeconds\":0,\"isSovrnReload\":false,\"isAboveTheFold\":false,\"adSize\":\"970x250\",\"adElementId\":\"#div-gpt-ad-reqbin_com-box-4-0\",\"type\":\"impression\"},{\"impressionId\":1689428230692,\"zoneId\":null,\"transactionId\":null,\"secondsInView\":0,\"gamAdUnitPath\":\"/1254144,21910826702/reqbin_com-box-1\",\"clicks\":0,\"viewableEngagedSeconds\":0,\"isSovrnReload\":false,\"isAboveTheFold\":true,\"adSize\":\"300x250\",\"adElementId\":\"#div-gpt-ad-reqbin_com-box-1-0\",\"type\":\"impression\"},{\"impressionId\":1689428203420,\"zoneId\":null,\"transactionId\":null,\"secondsInView\":0,\"gamAdUnitPath\":\"/1254144,21910826702/reqbin_com-banner-2\",\"clicks\":0,\"viewableEngagedSeconds\":0,\"isSovrnReload\":false,\"isAboveTheFold\":true,\"adSize\":\"300x250\",\"adElementId\":\"#div-gpt-ad-reqbin_com-banner-2-0\",\"type\":\"impression\"}]}" + } + }, + "response": { + "status": 200, + "statusText": "", + "httpVersion": "http/2.0", + "headers": [ + { + "name": "access-control-allow-origin", + "value": "*" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "date", + "value": "Sat, 15 Jul 2023 13:37:26 GMT" + }, + { + "name": "vary", + "value": "Origin" + } + ], + "cookies": [], + "content": { + "size": 0, + "mimeType": "text/plain", + "text": "" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": -1, + "_transferSize": 73, + "_error": null + }, + "serverIPAddress": "99.83.181.31", + "startedDateTime": "2023-07-15T13:37:26.093Z", + "time": 169.79599999582302, + "timings": { + "blocked": 0.6539999998793937, + "dns": 18.781000000000002, + "ssl": 55.379, + "connect": 96.754, + "send": 0.3190000000000026, + "wait": 53.01799999912642, + "receive": 0.2699999968172051, + "_blocked_queueing": 0.4079999998793937 + } + } + + ] + } +} \ No newline at end of file diff --git a/test/mitmproxy/data/har_files/with-bom.json b/test/mitmproxy/data/har_files/with-bom.json new file mode 100644 index 0000000000..08c8b8abbf --- /dev/null +++ b/test/mitmproxy/data/har_files/with-bom.json @@ -0,0 +1,173 @@ +[ + { + "id": "hardcoded_for_test", + "intercepted": false, + "is_replay": null, + "type": "http", + "modified": false, + "marked": "", + "comment": "", + "timestamp_created": 0, + "client_conn": { + "id": "hardcoded_for_test", + "peername": [ + "127.0.0.1", + 0 + ], + "sockname": [ + "127.0.0.1", + 0 + ], + "tls_established": false, + "cert": null, + "sni": null, + "cipher": null, + "alpn": null, + "tls_version": null, + "timestamp_start": 1689428246.093, + "timestamp_tls_setup": null, + "timestamp_end": 1689428246.262796 + }, + "server_conn": { + "id": "hardcoded_for_test", + "peername": null, + "sockname": null, + "address": [ + "99.83.181.31", + 443 + ], + "tls_established": false, + "cert": null, + "sni": null, + "cipher": null, + "alpn": null, + "tls_version": null, + "timestamp_start": null, + "timestamp_tcp_setup": null, + "timestamp_tls_setup": null, + "timestamp_end": null + }, + "request": { + "method": "POST", + "scheme": "https", + "host": "signal-metrics-collector-beta.s-onetag.com", + "port": 443, + "path": "/metrics", + "http_version": "HTTP/2", + "headers": [ + [ + ":authority", + "signal-metrics-collector-beta.s-onetag.com" + ], + [ + ":method", + "POST" + ], + [ + ":path", + "/metrics" + ], + [ + ":scheme", + "https" + ], + [ + "accept", + "*/*" + ], + [ + "accept-encoding", + "gzip, deflate, br" + ], + [ + "accept-language", + "en-US,en;q=0.9" + ], + [ + "cache-control", + "no-cache" + ], + [ + "content-length", + "1310" + ], + [ + "content-type", + "text/plain;charset=UTF-8" + ], + [ + "dnt", + "1" + ], + [ + "origin", + "https://reqbin.com" + ], + [ + "pragma", + "no-cache" + ], + [ + "sec-ch-ua", + "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"" + ], + [ + "sec-ch-ua-mobile", + "?0" + ], + [ + "sec-ch-ua-platform", + "\"macOS\"" + ], + [ + "sec-fetch-dest", + "empty" + ], + [ + "sec-fetch-mode", + "no-cors" + ], + [ + "sec-fetch-site", + "cross-site" + ], + [ + "user-agent", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" + ] + ], + "contentLength": 1310, + "contentHash": "94c0d23b4e9f828b4b9062885ba0b785ce53fc374aef106b01fa62ff9f15c35b", + "timestamp_start": 1689428246.093, + "timestamp_end": 1689428246.262796, + "pretty_host": "signal-metrics-collector-beta.s-onetag.com" + }, + "response": { + "http_version": "HTTP/2", + "status_code": 200, + "reason": "OK", + "headers": [ + [ + "access-control-allow-origin", + "*" + ], + [ + "content-length", + "0" + ], + [ + "date", + "Sat, 15 Jul 2023 13:37:26 GMT" + ], + [ + "vary", + "Origin" + ] + ], + "contentLength": 0, + "contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "timestamp_start": 1689428246.093, + "timestamp_end": 1689428246.262796 + } + } +] \ No newline at end of file diff --git a/test/mitmproxy/io/test_compat.py b/test/mitmproxy/io/test_compat.py index 35b11d6191..744a14610f 100644 --- a/test/mitmproxy/io/test_compat.py +++ b/test/mitmproxy/io/test_compat.py @@ -13,6 +13,7 @@ ["dumpfile-7-websocket.mitm", "https://echo.websocket.org/", 6], ["dumpfile-7.mitm", "https://example.com/", 2], ["dumpfile-10.mitm", "https://example.com/", 1], + ["dumpfile-19.mitm", "https://cloudflare-quic.com/", 1], ], ) def test_load(tdata, dumpfile, url, count): diff --git a/test/mitmproxy/io/test_tnetstring.py b/test/mitmproxy/io/test_tnetstring.py index a0207130cc..60fc4ad125 100644 --- a/test/mitmproxy/io/test_tnetstring.py +++ b/test/mitmproxy/io/test_tnetstring.py @@ -72,19 +72,19 @@ def test_roundtrip_format_examples(self): for data, expect in FORMAT_EXAMPLES.items(): self.assertEqual(expect, tnetstring.loads(data)) self.assertEqual(expect, tnetstring.loads(tnetstring.dumps(expect))) - self.assertEqual((expect, b""), tnetstring.pop(data)) + self.assertEqual((expect, b""), tnetstring.pop(memoryview(data))) def test_roundtrip_format_random(self): for _ in range(10): v = get_random_object() self.assertEqual(v, tnetstring.loads(tnetstring.dumps(v))) - self.assertEqual((v, b""), tnetstring.pop(tnetstring.dumps(v))) + self.assertEqual((v, b""), tnetstring.pop(memoryview(tnetstring.dumps(v)))) def test_roundtrip_format_unicode(self): for _ in range(10): v = get_random_object() self.assertEqual(v, tnetstring.loads(tnetstring.dumps(v))) - self.assertEqual((v, b""), tnetstring.pop(tnetstring.dumps(v))) + self.assertEqual((v, b""), tnetstring.pop(memoryview(tnetstring.dumps(v)))) def test_roundtrip_big_integer(self): # Recent Python versions do not like ints above 4300 digits, https://github.com/python/cpython/issues/95778 diff --git a/test/mitmproxy/net/data/verificationcerts/generate.py b/test/mitmproxy/net/data/verificationcerts/generate.py index 599e2c0dd5..570db7110f 100644 --- a/test/mitmproxy/net/data/verificationcerts/generate.py +++ b/test/mitmproxy/net/data/verificationcerts/generate.py @@ -1,6 +1,7 @@ """ Generate SSL test certificates. """ + import os import shlex import shutil @@ -91,3 +92,22 @@ def mkcert(cert, subject, ip: bool): pem.write(key.read()) shutil.copyfile("trusted-leaf.pem", "example.mitmproxy.org.pem") +with ( + open(f"trusted-leaf.crt") as crt, + open(f"self-signed.key") as key, + open(f"private-public-mismatch.pem", "w") as pem, +): + pem.write(crt.read()) + pem.write(key.read()) + +with ( + open(f"trusted-leaf.pem") as crt1, + open(f"trusted-root.crt") as crt2, + open(f"trusted-chain.pem", "w") as pem, +): + pem.write(crt1.read()) + pem.write(crt2.read()) + +with open(f"trusted-leaf.pem") as crt1, open(f"trusted-chain-invalid.pem", "w") as pem: + pem.write(crt1.read()) + pem.write("-----BEGIN CERTIFICATE-----\nnotacert\n-----END CERTIFICATE-----\n") diff --git a/test/mitmproxy/net/data/verificationcerts/private-public-mismatch.pem b/test/mitmproxy/net/data/verificationcerts/private-public-mismatch.pem new file mode 100644 index 0000000000..220559bf61 --- /dev/null +++ b/test/mitmproxy/net/data/verificationcerts/private-public-mismatch.pem @@ -0,0 +1,48 @@ +-----BEGIN CERTIFICATE----- +MIIDZDCCAkygAwIBAgIUSWoLwl7Rc//TKPwKwv25Vhb6uFAwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDExMDMwNzAzMjZaFw00MDEw +MjkwNzAzMjZaMDQxHjAcBgNVBAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzESMBAG +A1UECgwJbWl0bXByb3h5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +qcEdB7TZD7DxJlJH/ZTyrovP0din2vLCRZRZ07ix48arITGWj8wFJ/XpZsFmAWlH +2LriXGC8BB54EJt8Epix5tcdKvCZ/7vTgaBQ+DQVdCNiscaKwvDbigy037OY97sT +6Ou9xYjjgg0cb+WTkQGMOTMbCW2e5iuSvyMPdZ2+2RzbTcNV1/6O/5cQ7TOW2E83 +xeaN4stBMfRmsQRoHXBri0tqtQ3bHd3V4H9iai7HFBOcB/nsJUwLliZpz3j/dUD0 +yZAgdgB9XBlGvs/e746bGctyvl2QZu2JeACEVPmVrAUhqe2TVMVLDT17uzNeH1x5 +UXxdB4cexTOm4amvWSwvTQIDAQABo10wWzAfBgNVHSMEGDAWgBTkDj66Wmaf9YP0 +YMqGKG51PejxWzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAgBgNVHREEGTAXghVl +eGFtcGxlLm1pdG1wcm94eS5vcmcwDQYJKoZIhvcNAQELBQADggEBABwKrf+Gy1I5 +BnfhAqbDUYj8OVcjbB5esbvVYAADNNNQ10RREyz5OTTo2dSKy2hIVQeGxaBy5W6d +cNk0CoLzOgpgkwQPQ351+Y0C5yQztXIg/JM5aSeFuAbQg+NtzOQISrcDB390Xr2f +7YhyYL0XLX4NCP7ek7+lAClrf+lL9MysHTTP0pmFWLPP6AIR8JIsLpNpTDV10c8p +QcnJ8+5q6oLHNKN+M/HRcdKzj/XyJ538UzSOlmU+izhNT1j7mbszS0tc9yh0dmpP +9uuBY0wcD/NAHBpSX9v9ZJcOuWntsAxTbMXj1eWNRyt0QJLURlkqeVn6ZrE1/BDS +BqDdOKYJbkw= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAw1IZNjnWZOU8jJqlHVK45PLOpr+y8U0ks52OT6pDhTBWGFkn +hEffHAey/kSwSoszdb7e19VF0SLj4wXr36X7CKkJfFhzHrFOjg16ciNo0GRic82K +4VvlC0qRJVXakTVhN/Tm/zNL90GJLTBMti47jmDup52I8j39/PSb8n/6IWMfNMqt +6fqSDYfeATgzeK0jxG+SEpCm+iqeAdzLE3ZotZJMtZ3CTiQfZ5eJamHSJ8pURlZD +fha8JyS+DzeeIZEvA2QGWgDRigS4n20p7ykrwUxaUbLh2RV2n+kVy+CwgdsgFfE1 +40HI5MJ3WU7/TfoxcKUJF5gB3zmkhwD+s22i5QIDAQABAoIBADK7Gi1JbHQcTlO+ +vvAU0k00+5O36sRd4xB79cCfWpY3bcU5Mthayoo/PbBpKtjRuvX0M3EfxdiCFWqb +2R3nwIIJVZtkZdIs/1hKC+mlZM3rpN6rHk1WTvFV1sk5uWFJ2gxsoarbKfn4naaN +Cv+ulm1uo84JTs6MZ3HSHscnklIlNnDG3piC8JnzXVgS7kzbJPXTccZJI1Mwgyho +D1HoWatIep5XAp3OZePlApfRpKn/+2Hg6USkbcHYzX/XpA3b3/YEBqsXVUFxAs5m +nChdLpKUCIjcARInAXoULh0AQHGcH9dfJk1QF1Lw6nCoY12P1sZfdGU5trcslA1O +W28syoECgYEA6GjaqFYffceJHlODukHgpLNfa1EUy49ZWjmdmXTYXJpufzjD4n4H +sUkEnJ00ssaCVdd0XClbN/l/QvIAz3W8ZXXQWtZJHV2wAIyjWpqiOwaiXQFZIZ67 +kxGsLVjkuiST33CX6yl8IKAD+8B67uZhmWTnYBmxGnIZODqUatpqW3ECgYEA1yV+ +CGoNp6VQqej0t0y8C8pXiMGe2DGj5p1WFn00cn/fC1E2Yc0HG+E62OB7tgUFI180 +/nArOQHnTZCzAQAc44M63gesRMeu+0cxuTUqOUCn1lGD+4K/3IA59Rgzfvvnq6xu +tn2jidfqaDPfKavqtCqRbs8wJYaGEhgcb8pUvLUCgYEA4pjpKFvgFGip/lF7C+0T +NEJXdHD3j4lSmy+1w1szYQaJWa1k/73VjjsdLf3w1aXKihuprfn8oFS4ifMeayfl +6h62aPqpCuK/qal10+8U4ewT/g5Ecw0q4bfHYedcC0mCi8ZhuL0X809Q0vLWaXti +CYdiOEaUcK5yfGpRLuWJ8WECgYAWWXa2OQ4iFDJE9EY3pGkEcIiXVEXD/6QfGMkQ +nQENw+rPqigUENBkPQl37hnr1qmp+wHuTIiw61mz3Qw7Vl+p4sACwJlMq9GpmMO5 +kaRJPkYxJVaokfSMW2Wp6FGxJ0nxs3/sxTBv6VYYbQsJsSo4fROOh0dhHpBe4NJT +aplS4QKBgQCaMUN88HNaVr0+DPQKeFoflqwCCYsdK43QTWEirrFDWDliJ0k81DZJ +k7N3oR5UujsTMgfYDJ6Cp3enZVYyuoFnOlVT8v4XzvzAGTehyo4rMiE2TbMir7Xn +agPTZYSuQc4Iy7BPwh/PMlX6bDOTeq/ftyWrDuF9+pC5w3v4SkuMew== +-----END RSA PRIVATE KEY----- diff --git a/test/mitmproxy/net/data/verificationcerts/trusted-chain-invalid.pem b/test/mitmproxy/net/data/verificationcerts/trusted-chain-invalid.pem new file mode 100644 index 0000000000..ce51e2ce66 --- /dev/null +++ b/test/mitmproxy/net/data/verificationcerts/trusted-chain-invalid.pem @@ -0,0 +1,51 @@ +-----BEGIN CERTIFICATE----- +MIIDZDCCAkygAwIBAgIUSWoLwl7Rc//TKPwKwv25Vhb6uFAwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDExMDMwNzAzMjZaFw00MDEw +MjkwNzAzMjZaMDQxHjAcBgNVBAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzESMBAG +A1UECgwJbWl0bXByb3h5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +qcEdB7TZD7DxJlJH/ZTyrovP0din2vLCRZRZ07ix48arITGWj8wFJ/XpZsFmAWlH +2LriXGC8BB54EJt8Epix5tcdKvCZ/7vTgaBQ+DQVdCNiscaKwvDbigy037OY97sT +6Ou9xYjjgg0cb+WTkQGMOTMbCW2e5iuSvyMPdZ2+2RzbTcNV1/6O/5cQ7TOW2E83 +xeaN4stBMfRmsQRoHXBri0tqtQ3bHd3V4H9iai7HFBOcB/nsJUwLliZpz3j/dUD0 +yZAgdgB9XBlGvs/e746bGctyvl2QZu2JeACEVPmVrAUhqe2TVMVLDT17uzNeH1x5 +UXxdB4cexTOm4amvWSwvTQIDAQABo10wWzAfBgNVHSMEGDAWgBTkDj66Wmaf9YP0 +YMqGKG51PejxWzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAgBgNVHREEGTAXghVl +eGFtcGxlLm1pdG1wcm94eS5vcmcwDQYJKoZIhvcNAQELBQADggEBABwKrf+Gy1I5 +BnfhAqbDUYj8OVcjbB5esbvVYAADNNNQ10RREyz5OTTo2dSKy2hIVQeGxaBy5W6d +cNk0CoLzOgpgkwQPQ351+Y0C5yQztXIg/JM5aSeFuAbQg+NtzOQISrcDB390Xr2f +7YhyYL0XLX4NCP7ek7+lAClrf+lL9MysHTTP0pmFWLPP6AIR8JIsLpNpTDV10c8p +QcnJ8+5q6oLHNKN+M/HRcdKzj/XyJ538UzSOlmU+izhNT1j7mbszS0tc9yh0dmpP +9uuBY0wcD/NAHBpSX9v9ZJcOuWntsAxTbMXj1eWNRyt0QJLURlkqeVn6ZrE1/BDS +BqDdOKYJbkw= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAqcEdB7TZD7DxJlJH/ZTyrovP0din2vLCRZRZ07ix48arITGW +j8wFJ/XpZsFmAWlH2LriXGC8BB54EJt8Epix5tcdKvCZ/7vTgaBQ+DQVdCNiscaK +wvDbigy037OY97sT6Ou9xYjjgg0cb+WTkQGMOTMbCW2e5iuSvyMPdZ2+2RzbTcNV +1/6O/5cQ7TOW2E83xeaN4stBMfRmsQRoHXBri0tqtQ3bHd3V4H9iai7HFBOcB/ns +JUwLliZpz3j/dUD0yZAgdgB9XBlGvs/e746bGctyvl2QZu2JeACEVPmVrAUhqe2T +VMVLDT17uzNeH1x5UXxdB4cexTOm4amvWSwvTQIDAQABAoIBAEb3arF8E3qR2F7S +6zHCASqjXIA3+QR5lGoOOPdgMU4uEgDQgEchXc506dyBYamZX+XlSxifgDqgmkUn +G1mS6Fy+9XysFVVqKmP4p6D79TQWTv5PKFeS5dTytvMGXB7E4O/xDeb08Ve/L3JA +Ic7vPLX0/YqVf2ZuNO0fNSlQhyawUVlSS6yq/B1GUo44PX/PXrWYZd66mc29g+KF +7D0nnbloLY+5QmOEVYbf99RHJ64Cwxzwxi4ic9AxLaNMfkrydjbGQ0VhJq14WEux +/TJLvinzIDyslnx4aYstno3ryoxLtR/9ALysrdQ8vVMaVCdbf0aMu832R2dI4s9K +ixQlgmkCgYEA0Ho0a4qzwk9oLWYk1x16kOCqmfuenlEz3Tv8uBB/jdz7UM63sS3h +OUQYKhhtzOGf6CDA3CE11ie6SX7zHrowPLJBSpacJZJcrHPGZxdBZ/As/QpGnZll +1eTMlVRXk06k/fEYplU1dS5IDbsvUIaaF9CF9Qd3MkDRglhbM19Iy+sCgYEA0HM1 +d7OBsjSi09zFDE+Joq6Gih8LqqFLtMsIHEKAJ0gJgmt6MTfjtdPo55ZKVLCR2pbP +yRHagK4LRUFY9Pl5eGlEUF9cKEKKtZOURUFVz3yBMYPBje/B1o/UCCj+nr2reWgx +qj/jwZrph6QKCkEsnQXi98tE7XSgihUh6UEQO6cCgYASVe0uWDCfMmSzOXyb/te8 +zkWy7VJyEipBlvkPJ0RQsdLYtJWrW6Gna7nEWgmuL1nlDJxpv/IAN9ZGiIfReAau +D+92I/DvzQOhlz0n6/+wqIsMZk73pXozacAkkhpxtkUEoKPOXUgqWju0GXZ72prK +5WgiuNle7hx/Hk5HImZAqQKBgQCK7W4iRGpZeklXiNlvtgcWfNlAbyaYZ34MlhDm +vM+q3pEv8i/zY7uJcR3WU81gmnnrRP5hlVuazeTHGKGQTEFQJmCYbKYAUzEdiamV +atElQ2bbuGOlFLmNJjj7406oP+NsPCx1urUyUOv6MjNa2EtCsCywWDKtTEC/Jwx9 +6JZIGwKBgDa4Ephl+lcyGC8D9Tdc4Nme6n/10pIN53ZCplqVSuma+kOOQX7ZXpJb +0csHR9KODcpQuo2yOnUfZ1z4+tsjms2Uv97GgcZ9sO84I/3RGJCvxmzAEiRmJMfH +y38GtEYCnat5VOKdo//eIYtiu9YSXuuS1ENSWUPZ9YInrkUk0j8S +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +notacert +-----END CERTIFICATE----- diff --git a/test/mitmproxy/net/data/verificationcerts/trusted-chain.pem b/test/mitmproxy/net/data/verificationcerts/trusted-chain.pem new file mode 100644 index 0000000000..0f41465105 --- /dev/null +++ b/test/mitmproxy/net/data/verificationcerts/trusted-chain.pem @@ -0,0 +1,69 @@ +-----BEGIN CERTIFICATE----- +MIIDZDCCAkygAwIBAgIUSWoLwl7Rc//TKPwKwv25Vhb6uFAwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDExMDMwNzAzMjZaFw00MDEw +MjkwNzAzMjZaMDQxHjAcBgNVBAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzESMBAG +A1UECgwJbWl0bXByb3h5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +qcEdB7TZD7DxJlJH/ZTyrovP0din2vLCRZRZ07ix48arITGWj8wFJ/XpZsFmAWlH +2LriXGC8BB54EJt8Epix5tcdKvCZ/7vTgaBQ+DQVdCNiscaKwvDbigy037OY97sT +6Ou9xYjjgg0cb+WTkQGMOTMbCW2e5iuSvyMPdZ2+2RzbTcNV1/6O/5cQ7TOW2E83 +xeaN4stBMfRmsQRoHXBri0tqtQ3bHd3V4H9iai7HFBOcB/nsJUwLliZpz3j/dUD0 +yZAgdgB9XBlGvs/e746bGctyvl2QZu2JeACEVPmVrAUhqe2TVMVLDT17uzNeH1x5 +UXxdB4cexTOm4amvWSwvTQIDAQABo10wWzAfBgNVHSMEGDAWgBTkDj66Wmaf9YP0 +YMqGKG51PejxWzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAgBgNVHREEGTAXghVl +eGFtcGxlLm1pdG1wcm94eS5vcmcwDQYJKoZIhvcNAQELBQADggEBABwKrf+Gy1I5 +BnfhAqbDUYj8OVcjbB5esbvVYAADNNNQ10RREyz5OTTo2dSKy2hIVQeGxaBy5W6d +cNk0CoLzOgpgkwQPQ351+Y0C5yQztXIg/JM5aSeFuAbQg+NtzOQISrcDB390Xr2f +7YhyYL0XLX4NCP7ek7+lAClrf+lL9MysHTTP0pmFWLPP6AIR8JIsLpNpTDV10c8p +QcnJ8+5q6oLHNKN+M/HRcdKzj/XyJ538UzSOlmU+izhNT1j7mbszS0tc9yh0dmpP +9uuBY0wcD/NAHBpSX9v9ZJcOuWntsAxTbMXj1eWNRyt0QJLURlkqeVn6ZrE1/BDS +BqDdOKYJbkw= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAqcEdB7TZD7DxJlJH/ZTyrovP0din2vLCRZRZ07ix48arITGW +j8wFJ/XpZsFmAWlH2LriXGC8BB54EJt8Epix5tcdKvCZ/7vTgaBQ+DQVdCNiscaK +wvDbigy037OY97sT6Ou9xYjjgg0cb+WTkQGMOTMbCW2e5iuSvyMPdZ2+2RzbTcNV +1/6O/5cQ7TOW2E83xeaN4stBMfRmsQRoHXBri0tqtQ3bHd3V4H9iai7HFBOcB/ns +JUwLliZpz3j/dUD0yZAgdgB9XBlGvs/e746bGctyvl2QZu2JeACEVPmVrAUhqe2T +VMVLDT17uzNeH1x5UXxdB4cexTOm4amvWSwvTQIDAQABAoIBAEb3arF8E3qR2F7S +6zHCASqjXIA3+QR5lGoOOPdgMU4uEgDQgEchXc506dyBYamZX+XlSxifgDqgmkUn +G1mS6Fy+9XysFVVqKmP4p6D79TQWTv5PKFeS5dTytvMGXB7E4O/xDeb08Ve/L3JA +Ic7vPLX0/YqVf2ZuNO0fNSlQhyawUVlSS6yq/B1GUo44PX/PXrWYZd66mc29g+KF +7D0nnbloLY+5QmOEVYbf99RHJ64Cwxzwxi4ic9AxLaNMfkrydjbGQ0VhJq14WEux +/TJLvinzIDyslnx4aYstno3ryoxLtR/9ALysrdQ8vVMaVCdbf0aMu832R2dI4s9K +ixQlgmkCgYEA0Ho0a4qzwk9oLWYk1x16kOCqmfuenlEz3Tv8uBB/jdz7UM63sS3h +OUQYKhhtzOGf6CDA3CE11ie6SX7zHrowPLJBSpacJZJcrHPGZxdBZ/As/QpGnZll +1eTMlVRXk06k/fEYplU1dS5IDbsvUIaaF9CF9Qd3MkDRglhbM19Iy+sCgYEA0HM1 +d7OBsjSi09zFDE+Joq6Gih8LqqFLtMsIHEKAJ0gJgmt6MTfjtdPo55ZKVLCR2pbP +yRHagK4LRUFY9Pl5eGlEUF9cKEKKtZOURUFVz3yBMYPBje/B1o/UCCj+nr2reWgx +qj/jwZrph6QKCkEsnQXi98tE7XSgihUh6UEQO6cCgYASVe0uWDCfMmSzOXyb/te8 +zkWy7VJyEipBlvkPJ0RQsdLYtJWrW6Gna7nEWgmuL1nlDJxpv/IAN9ZGiIfReAau +D+92I/DvzQOhlz0n6/+wqIsMZk73pXozacAkkhpxtkUEoKPOXUgqWju0GXZ72prK +5WgiuNle7hx/Hk5HImZAqQKBgQCK7W4iRGpZeklXiNlvtgcWfNlAbyaYZ34MlhDm +vM+q3pEv8i/zY7uJcR3WU81gmnnrRP5hlVuazeTHGKGQTEFQJmCYbKYAUzEdiamV +atElQ2bbuGOlFLmNJjj7406oP+NsPCx1urUyUOv6MjNa2EtCsCywWDKtTEC/Jwx9 +6JZIGwKBgDa4Ephl+lcyGC8D9Tdc4Nme6n/10pIN53ZCplqVSuma+kOOQX7ZXpJb +0csHR9KODcpQuo2yOnUfZ1z4+tsjms2Uv97GgcZ9sO84I/3RGJCvxmzAEiRmJMfH +y38GtEYCnat5VOKdo//eIYtiu9YSXuuS1ENSWUPZ9YInrkUk0j8S +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDazCCAlOgAwIBAgIUB5WLNdtHRvciUwDfySAEHYVSNe0wDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDExMDMwNzAzMjZaFw00MDEw +MjkwNzAzMjZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDVWUg2YdsztWIZpsWdbIB6Aewa1Igt7mNkKMQ1NJ6v +priVlzWhZr0FfSVTid2m3Od2f5A751Q+IXLkNJ8d6Y4qVirAstEM57sCH/Hmt1E3 +cZOAzLQY2xCIrKPmbu6d8eSGO1q+Y8KstCK/V94/QRahjjoHxkLcSAmdg6PAkbhB +7MwOxiJslIbsBY4UCXP0l4kUUIuMi8W2Y4M1VgvLRpUjaKVo1NQ0hLi4XBnU7Bsq +A8/PZDuVeP0NcJtAxRicqqLX/MjgkTrA2tPnSj9m60lO79S40GSzB238o2zJQ5ON +jHJdAhLlrsrkxZmDmKM59IdmV2OhN7O844ktbXDOqvq5AgMBAAGjUzBRMB0GA1Ud +DgQWBBTkDj66Wmaf9YP0YMqGKG51PejxWzAfBgNVHSMEGDAWgBTkDj66Wmaf9YP0 +YMqGKG51PejxWzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAo +9FwbGob1WRAo7ORShaDhopIDAYMCL1oc9YZ2ZQK8aDuZbqIZ/7+1LbWCeMAV4PTH +Tcx+n9Zg/g/RkoSNu8KqFoQGFmdBZnKOMU4vlITu/ORpDu1sjSA+Eo9YbipemX+n +jv+YHI4STFAWnyext3IUZVkT6wpU3pwUjX0fbk4LJfVLR41y4iD11XGergxAcpjj +T03txkJcrTiX65SnB041Y4exUMLOUn5lTs/q2rBNkiLNljXQ6l+8L1rdQEN/j0Mx +OYdc6FIUIESC1mMOf80+YOwxPJ862SyTv/cJB3npwTj/DdQu7blf/z2hMP7a7w+X +l5d31XzcDOrCf/bTthvb +-----END CERTIFICATE----- diff --git a/test/mitmproxy/net/dns/test_domain_names.py b/test/mitmproxy/net/dns/test_domain_names.py index 1d0f54d6cc..72467ed270 100644 --- a/test/mitmproxy/net/dns/test_domain_names.py +++ b/test/mitmproxy/net/dns/test_domain_names.py @@ -4,11 +4,12 @@ import pytest from mitmproxy.net.dns import domain_names +from mitmproxy.net.dns import types def test_unpack_from_with_compression(): assert domain_names.unpack_from_with_compression( - b"\xFF\x03www\x07example\x03org\x00", 1, domain_names.cache() + b"\xff\x03www\x07example\x03org\x00", 1, domain_names.cache() ) == ( "www.example.org", 17, @@ -20,7 +21,7 @@ def test_unpack_from_with_compression(): b"\x03www\xc0\x00", 0, domain_names.cache() ) assert domain_names.unpack_from_with_compression( - b"\xFF\xFF\xFF\x07example\x03org\x00\xFF\xFF\xFF\x03www\xc0\x03", + b"\xff\xff\xff\x07example\x03org\x00\xff\xff\xff\x03www\xc0\x03", 19, domain_names.cache(), ) == ("www.example.org", 6) @@ -31,7 +32,7 @@ def test_unpack(): with pytest.raises( struct.error, match=re.escape("unpack requires a buffer of 17 bytes") ): - domain_names.unpack(b"\x03www\x07example\x03org\x00\xFF") + domain_names.unpack(b"\x03www\x07example\x03org\x00\xff") with pytest.raises( struct.error, match=re.escape("unpack encountered a pointer which is not supported in RDATA"), @@ -47,7 +48,7 @@ def test_unpack(): domain_names.unpack(b"\x40" + (b"a" * 64) + b"\x00") with pytest.raises( struct.error, - match=re.escape("unpack encountered a illegal characters at offset 1"), + match=re.escape("unpack encountered an illegal characters at offset 1"), ): domain_names.unpack(b"\x03\xff\xff\xff\00") @@ -66,3 +67,35 @@ def test_pack(): ): domain_names.pack(name) assert domain_names.pack("www.example.org") == b"\x03www\x07example\x03org\x00" + + +def test_record_data_can_have_compression(): + assert domain_names.record_data_can_have_compression(types.NS) + assert not domain_names.record_data_can_have_compression(types.HTTPS) + + +def test_decompress_from_record_data(): + buffer = ( + b"\x10}\x81\x80\x00\x01\x00\x01\x00\x00\x00\x01\x06google\x03com\x00\x00\x06\x00\x01\xc0\x0c\x00\x06\x00" + + b"\x01\x00\x00\x00\x0c\x00&\x03ns1\xc0\x0c\tdns-admin\xc0\x0c&~gw\x00\x00\x03\x84\x00\x00\x03\x84\x00" + + b"\x00\x07\x08\x00\x00\x00<\x00\x00)\x02\x00\x00\x00\x00\x00\x00\x00" + ) + assert ( + domain_names.decompress_from_record_data(buffer, 40, 78, domain_names.cache()) + == b"\x03ns1\x06google\x03com\x00\tdns-admin\x06google\x03com\x00&~gw\x00\x00\x03\x84\x00\x00\x03\x84\x00" + + b"\x00\x07\x08\x00\x00\x00<" + ) + + +def test_record_data_contains_fake_pointer(): + # \xd2\a2 and \xc2\x00 seem like domain name compression pointers but are actually part of some other data type + buffer = ( + b"\xfc\xc7\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06google\x03com\x00\x00\x06\x00\x01\xc0\x0c\x00\x06\x00" + + b"\x01\x00\x00\x008\x00&\x03ns1\xc0\x0c\tdns-admin\xc0\x0c&\xd2\xa2\xc2\x00\x00\x03\x84\x00\x00\x03\x84\x00" + + b"\x00\x07\x08\x00\x00\x00<" + ) + assert ( + domain_names.decompress_from_record_data(buffer, 40, 78, domain_names.cache()) + == b"\x03ns1\x06google\x03com\x00\tdns-admin\x06google\x03com\x00&\xd2\xa2\xc2\x00\x00\x03\x84\x00\x00\x03" + + b"\x84\x00\x00\x07\x08\x00\x00\x00<" + ) diff --git a/test/mitmproxy/net/dns/test_https_records.py b/test/mitmproxy/net/dns/test_https_records.py new file mode 100644 index 0000000000..77db528505 --- /dev/null +++ b/test/mitmproxy/net/dns/test_https_records.py @@ -0,0 +1,109 @@ +import re +import struct + +import pytest +from hypothesis import given +from hypothesis import strategies as st + +from mitmproxy.net.dns import https_records + + +class TestHTTPSRecords: + def test_simple(self): + assert https_records.SVCParamKeys.ALPN.value == 1 + assert https_records.SVCParamKeys(1).name == "ALPN" + + def test_httpsrecord(self): + with pytest.raises( + TypeError, + match=re.escape( + "HTTPSRecord.__init__() missing 3 required positional arguments: 'priority', 'target_name', and 'params'" + ), + ): + https_records.HTTPSRecord() + + def test_unpack(self): + params = { + 0: b"\x00\x04\x00\x06", + 1: b"\x02h2\x02h3", + 2: b"", + 3: b"\x01\xbb", + 4: b"\xb9\xc7l\x99\xb9\xc7m\x99\xb9\xc7n\x99\xb9\xc7o\x99", + 5: b"testbytes", + 6: b"&\x06P\xc0\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01S", + } + record = https_records.HTTPSRecord(1, "example.com", params) + assert https_records.unpack(https_records.pack(record)) == record + + with pytest.raises( + struct.error, match=re.escape("unpack requires a buffer of 2 bytes") + ): + https_records.unpack(b"") + + with pytest.raises( + struct.error, + match=re.escape("unpack encountered an illegal characters at offset 3"), + ): + https_records.unpack( + b"\x00\x01\x07exampl\x87\x03com\x00\x00\x01\x00\x06\x02h2\x02h3" + ) + + with pytest.raises( + struct.error, match=re.escape("unpack requires a buffer of 25 bytes") + ): + https_records.unpack( + b"\x00\x01\x07example\x03com\x00\x00\x01\x00\x06\x02h2" + ) + + with pytest.raises( + struct.error, match=re.escape("unpack requires a label buffer of 7 bytes") + ): + https_records.unpack(b"\x00\x01\x07exa") + + def test_pack(self): + params = { + 0: b"\x00\x04\x00\x06", + 1: b"\x02h2\x02h3", + 2: b"", + 3: b"\x01\xbb", + 4: b"\xb9\xc7l\x99\xb9\xc7m\x99\xb9\xc7n\x99\xb9\xc7o\x99", + 5: b"testbytes", + 6: b"&\x06P\xc0\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01S", + } + record = https_records.HTTPSRecord(1, "example.com", params) + assert ( + https_records.pack(record) + == b"\x00\x01\x07example\x03com\x00\x00\x00\x00\x04\x00\x04\x00\x06\x00\x01\x00\x06\x02h2\x02h3\x00\x02\x00\x00\x00\x03\x00\x02\x01\xbb\x00\x04\x00\x10\xb9\xc7l\x99\xb9\xc7m\x99\xb9\xc7n\x99\xb9\xc7o\x99\x00\x05\x00\ttestbytes\x00\x06\x00@&\x06P\xc0\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01S&\x06P\xc0\x80\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01S" + ) + + record = https_records.HTTPSRecord(1, "", {}) + assert https_records.pack(record) == b"\x00\x01\x00" + + @given(st.binary()) + def test_fuzz_unpack(self, data: bytes): + try: + https_records.unpack(data) + except struct.error: + pass + + def test_str(self): + params = { + 0: b"\x00", + 1: b"\x01", + 2: b"", + 3: b"\x02", + 4: b"\x03", + 5: b"\x04", + 6: b"\x05", + } + record = https_records.HTTPSRecord(1, "example.com", params) + assert ( + str(record) + == "priority: 1 target_name: 'example.com' {'mandatory': b'\\x00', 'alpn': b'\\x01', 'no_default_alpn': b'', 'port': b'\\x02', 'ipv4hint': b'\\x03', 'ech': b'\\x04', 'ipv6hint': b'\\x05'}" + ) + + params = {111: b"\x00"} + record = https_records.HTTPSRecord(1, "example.com", params) + assert ( + str(record) == "priority: 1 target_name: 'example.com' {'key111': b'\\x00'}" + ) diff --git a/test/mitmproxy/net/http/http1/test_read.py b/test/mitmproxy/net/http/http1/test_read.py index a9148e7abc..09441e96ca 100644 --- a/test/mitmproxy/net/http/http1/test_read.py +++ b/test/mitmproxy/net/http/http1/test_read.py @@ -123,7 +123,7 @@ def test_expected_http_body_size(): with pytest.raises(ValueError, match="Invalid transfer encoding"): expected_http_body_size( treq( - headers=Headers(transfer_encoding="chun\u212Aed") + headers=Headers(transfer_encoding="chun\u212aed") ), # "chunKed".lower() == "chunked" ) with pytest.raises(ValueError, match="Unknown transfer encoding"): diff --git a/test/mitmproxy/net/http/test_headers.py b/test/mitmproxy/net/http/test_headers.py index 473b930f84..f91f46dea9 100644 --- a/test/mitmproxy/net/http/test_headers.py +++ b/test/mitmproxy/net/http/test_headers.py @@ -1,6 +1,9 @@ import collections +import pytest + from mitmproxy.net.http.headers import assemble_content_type +from mitmproxy.net.http.headers import infer_content_encoding from mitmproxy.net.http.headers import parse_content_type @@ -25,3 +28,34 @@ def test_assemble_content_type(): ) == "text/html; charset=utf8; foo=bar" ) + + +@pytest.mark.parametrize( + "content_type,content,expected", + [ + ("", b"", "latin-1"), + ("", b"foo", "latin-1"), + ("", b"\xfc", "latin-1"), + ("", b"\xf0\xe2", "latin-1"), + ("text/html; charset=latin1", b"\xc3\xbc", "latin1"), + ("text/html; charset=utf8", b"\xc3\xbc", "utf8"), + # json + ("application/json", b'"\xc3\xbc"', "utf8"), + # meta charset + ( + "text/html", + b'\xe6\x98\x8e\xe4\xbc\xaf', + "gb18030", + ), + # css charset + ( + "text/css", + b'@charset "gb2312";' b'#foo::before {content: "\xe6\x98\x8e\xe4\xbc\xaf"}', + "gb18030", + ), + ], +) +def test_infer_content_encoding(content_type, content, expected): + # Additional test coverage in `test_http::TestMessageText` + assert infer_content_encoding(content_type, content) == expected diff --git a/test/mitmproxy/net/test_encoding.py b/test/mitmproxy/net/test_encoding.py index 640d318aef..f3b79523a9 100644 --- a/test/mitmproxy/net/test_encoding.py +++ b/test/mitmproxy/net/test_encoding.py @@ -93,3 +93,22 @@ def test_cache(): # This is not in the cache anymore assert encoding.encode(b"decoded", "gzip") == b"encoded" assert encode_gzip.call_count == 1 + + +def test_zstd(): + FRAME_SIZE = 1024 + + # Create payload of 1024b + test_content = "a" * FRAME_SIZE + + # Compress it, will result a single frame + single_frame = encoding.encode_zstd(test_content.encode()) + + # Concat compressed frame, it'll result two frames, total size of 2048b payload + two_frames = single_frame + single_frame + + # Uncompressed single frame should have the size of FRAME_SIZE + assert len(encoding.decode_zstd(single_frame)) == FRAME_SIZE + + # Uncompressed two frames should have the size of FRAME_SIZE * 2 + assert len(encoding.decode_zstd(two_frames)) == FRAME_SIZE * 2 diff --git a/test/mitmproxy/net/test_tls.py b/test/mitmproxy/net/test_tls.py index 58e97b3dee..4af6918009 100644 --- a/test/mitmproxy/net/test_tls.py +++ b/test/mitmproxy/net/test_tls.py @@ -1,5 +1,6 @@ from pathlib import Path +import pytest from OpenSSL import crypto from OpenSSL import SSL @@ -7,6 +8,13 @@ from mitmproxy.net import tls +@pytest.mark.parametrize("version", [tls.Version.UNBOUNDED, tls.Version.SSL3]) +def test_supported(version): + # wild assumption: test environments should not do SSLv3 by default. + expected_support = version is tls.Version.UNBOUNDED + assert tls.is_supported_version(version) == expected_support + + def test_make_master_secret_logger(): assert tls.make_master_secret_logger(None) is None assert isinstance(tls.make_master_secret_logger("filepath"), tls.MasterSecretLogger) diff --git a/test/mitmproxy/net/test_udp.py b/test/mitmproxy/net/test_udp.py deleted file mode 100644 index b8f5250943..0000000000 --- a/test/mitmproxy/net/test_udp.py +++ /dev/null @@ -1,102 +0,0 @@ -import asyncio - -import pytest - -from mitmproxy.connection import Address -from mitmproxy.net.udp import DatagramReader -from mitmproxy.net.udp import DatagramWriter -from mitmproxy.net.udp import MAX_DATAGRAM_SIZE -from mitmproxy.net.udp import open_connection -from mitmproxy.net.udp import start_server - - -async def test_client_server(): - server_reader = DatagramReader() - server_writer: DatagramWriter | None = None - - def handle_datagram( - transport: asyncio.DatagramTransport, - data: bytes, - remote_addr: Address, - local_addr: Address, - ): - nonlocal server_reader, server_writer - if server_writer is None: - server_writer = DatagramWriter(transport, remote_addr, server_reader) - server_reader.feed_data(data, remote_addr) - - server = await start_server(handle_datagram, "127.0.0.1", 0) - assert repr(server).startswith(" context.Context: ) -settings.register_profile("fast", max_examples=10) +settings.register_profile("fast", max_examples=10, deadline=None) settings.register_profile("deep", max_examples=100_000, deadline=None) settings.load_profile(os.getenv("HYPOTHESIS_PROFILE", "fast")) diff --git a/test/mitmproxy/proxy/layers/http/hyper_h2_test_helpers.py b/test/mitmproxy/proxy/layers/http/hyper_h2_test_helpers.py index 9b1e2676df..2932ad8356 100644 --- a/test/mitmproxy/proxy/layers/http/hyper_h2_test_helpers.py +++ b/test/mitmproxy/proxy/layers/http/hyper_h2_test_helpers.py @@ -7,6 +7,7 @@ This module contains helpers for the h2 tests. """ + from hpack.hpack import Encoder from hyperframe.frame import AltSvcFrame from hyperframe.frame import ContinuationFrame diff --git a/test/mitmproxy/proxy/layers/http/test_http.py b/test/mitmproxy/proxy/layers/http/test_http.py index 273179bdf3..f55162ea1c 100644 --- a/test/mitmproxy/proxy/layers/http/test_http.py +++ b/test/mitmproxy/proxy/layers/http/test_http.py @@ -64,16 +64,23 @@ def test_http_proxy(tctx): @pytest.mark.parametrize("strategy", ["lazy", "eager"]) -def test_https_proxy(strategy, tctx): +@pytest.mark.parametrize("http_connect_send_host_header", [True, False]) +def test_https_proxy(strategy, http_connect_send_host_header, tctx): """Test a CONNECT request, followed by a HTTP GET /""" server = Placeholder(Server) flow = Placeholder(HTTPFlow) playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular)) tctx.options.connection_strategy = strategy + tctx.options.http_connect_send_host_header = http_connect_send_host_header ( playbook - >> DataReceived(tctx.client, b"CONNECT example.proxy:80 HTTP/1.1\r\n\r\n") + >> DataReceived( + tctx.client, + b"CONNECT example.proxy:80 HTTP/1.1" + + (b"\r\nHost: example.com:80" if http_connect_send_host_header else b"") + + b"\r\n\r\n", + ) << http.HttpConnectHook(Placeholder()) >> reply() ) @@ -82,6 +89,8 @@ def test_https_proxy(strategy, tctx): playbook >> reply(None) ( playbook + << http.HttpConnectedHook(Placeholder()) + >> reply(None) << SendData(tctx.client, b"HTTP/1.1 200 Connection established\r\n\r\n") >> DataReceived( tctx.client, b"GET /foo?hello=1 HTTP/1.1\r\nHost: example.com\r\n\r\n" @@ -133,7 +142,10 @@ def redirect(flow: HTTPFlow): flow.request.url = "http://redirected.site/" if https_client: - p >> DataReceived(tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\n\r\n") + p >> DataReceived( + tctx.client, + b"CONNECT example.com:80 HTTP/1.1\r\nHost: example.com:80\r\n\r\n", + ) if strategy == "eager": p << OpenConnection(Placeholder()) p >> reply(None) @@ -295,11 +307,16 @@ def test_disconnect_while_intercept(tctx): assert ( Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False) - >> DataReceived(tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\n\r\n") + >> DataReceived( + tctx.client, + b"CONNECT example.com:80 HTTP/1.1\r\nHost: example.com:80\r\n\r\n", + ) << http.HttpConnectHook(Placeholder(HTTPFlow)) >> reply() << OpenConnection(server1) >> reply(None) + << http.HttpConnectedHook(Placeholder(HTTPFlow)) + >> reply(None) << SendData(tctx.client, b"HTTP/1.1 200 Connection established\r\n\r\n") >> DataReceived(tctx.client, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") << layer.NextLayerHook(Placeholder()) @@ -665,7 +682,8 @@ def test_server_unreachable(tctx, connect): playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False) if connect: playbook >> DataReceived( - tctx.client, b"CONNECT example.com:443 HTTP/1.1\r\n\r\n" + tctx.client, + b"CONNECT example.com:443 HTTP/1.1\r\nHost: example.com:443\r\n\r\n", ) else: playbook >> DataReceived( @@ -675,12 +693,10 @@ def test_server_unreachable(tctx, connect): playbook << OpenConnection(server) playbook >> reply("Connection failed") if not connect: - # Our API isn't ideal here, there is no error hook for CONNECT requests currently. - # We could fix this either by having CONNECT request go through all our regular hooks, - # or by adding dedicated ok/error hooks. - # See also: test_connect_unauthorized playbook << http.HttpErrorHook(flow) - playbook >> reply() + else: + playbook << http.HttpConnectErrorHook(flow) + playbook >> reply() playbook << SendData( tctx.client, BytesMatching(b"502 Bad Gateway.+Connection failed") ) @@ -688,9 +704,9 @@ def test_server_unreachable(tctx, connect): playbook << CloseConnection(tctx.client) assert playbook + assert not flow().live if not connect: assert flow().error - assert not flow().live @pytest.mark.parametrize( @@ -760,14 +776,20 @@ def test_upstream_proxy(tctx, redirect, domain, scheme): else: assert ( playbook - >> DataReceived(tctx.client, b"CONNECT %s:443 HTTP/1.1\r\n\r\n" % domain) + >> DataReceived( + tctx.client, + b"CONNECT %s:443 HTTP/1.1\r\nHost: %s:443\r\n\r\n" % (domain, domain), + ) << SendData(tctx.client, b"HTTP/1.1 200 Connection established\r\n\r\n") >> DataReceived(tctx.client, b"GET / HTTP/1.1\r\nHost: %s\r\n\r\n" % domain) << layer.NextLayerHook(Placeholder()) >> reply_next_layer(lambda ctx: http.HttpLayer(ctx, HTTPMode.transparent)) << OpenConnection(server) >> reply(None) - << SendData(server, b"CONNECT %s:443 HTTP/1.1\r\n\r\n" % domain) + << SendData( + server, + b"CONNECT %s:443 HTTP/1.1\r\nHost: %s:443\r\n\r\n" % (domain, domain), + ) >> DataReceived(server, b"HTTP/1.1 200 Connection established\r\n\r\n") << SendData(server, b"GET / HTTP/1.1\r\nHost: %s\r\n\r\n" % domain) ) @@ -819,13 +841,18 @@ def test_upstream_proxy(tctx, redirect, domain, scheme): else: if redirect == "change-destination": playbook << SendData( - server2, b"CONNECT %s.test:443 HTTP/1.1\r\n\r\n" % domain + server2, + b"CONNECT %s.test:443 HTTP/1.1\r\nHost: %s.test:443\r\n\r\n" + % (domain, domain), ) playbook >> DataReceived( server2, b"HTTP/1.1 200 Connection established\r\n\r\n" ) elif redirect == "change-proxy": - playbook << SendData(server2, b"CONNECT %s:443 HTTP/1.1\r\n\r\n" % domain) + playbook << SendData( + server2, + b"CONNECT %s:443 HTTP/1.1\r\nHost: %s:443\r\n\r\n" % (domain, domain), + ) playbook >> DataReceived( server2, b"HTTP/1.1 200 Connection established\r\n\r\n" ) @@ -869,7 +896,9 @@ def test_http_proxy_tcp(tctx, mode, close_first): playbook = Playbook(toplayer, hooks=False) assert ( playbook - >> DataReceived(tctx.client, b"CONNECT example:443 HTTP/1.1\r\n\r\n") + >> DataReceived( + tctx.client, b"CONNECT example:443 HTTP/1.1\r\nHost: example:443\r\n\r\n" + ) << SendData(tctx.client, b"HTTP/1.1 200 Connection established\r\n\r\n") >> DataReceived(tctx.client, b"this is not http") << layer.NextLayerHook(Placeholder()) @@ -881,7 +910,9 @@ def test_http_proxy_tcp(tctx, mode, close_first): playbook >> reply(None) if mode == "upstream": - playbook << SendData(server, b"CONNECT example:443 HTTP/1.1\r\n\r\n") + playbook << SendData( + server, b"CONNECT example:443 HTTP/1.1\r\nHost: example:443\r\n\r\n" + ) playbook >> DataReceived(server, b"HTTP/1.1 200 Connection established\r\n\r\n") assert ( @@ -923,13 +954,17 @@ def test_proxy_chain(tctx, strategy): tctx.options.connection_strategy = strategy playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False) - playbook >> DataReceived(tctx.client, b"CONNECT proxy:8080 HTTP/1.1\r\n\r\n") + playbook >> DataReceived( + tctx.client, b"CONNECT proxy:8080 HTTP/1.1\r\nHost: proxy:8080\r\n\r\n" + ) if strategy == "eager": playbook << OpenConnection(server) playbook >> reply(None) playbook << SendData(tctx.client, b"HTTP/1.1 200 Connection established\r\n\r\n") - playbook >> DataReceived(tctx.client, b"CONNECT second-proxy:8080 HTTP/1.1\r\n\r\n") + playbook >> DataReceived( + tctx.client, b"CONNECT second-proxy:8080 HTTP/1.1\r\nHost: proxy:8080\r\n\r\n" + ) playbook << layer.NextLayerHook(Placeholder()) playbook >> reply_next_layer(lambda ctx: http.HttpLayer(ctx, HTTPMode.transparent)) playbook << SendData( @@ -1188,7 +1223,9 @@ def assert_kill(err_hook: bool = True): playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular)) assert ( playbook - >> DataReceived(tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\n\r\n") + >> DataReceived( + tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\nHost: example:80\r\n\r\n" + ) << http.HttpConnectHook(connect_flow) ) if when == "http_connect": @@ -1196,6 +1233,8 @@ def assert_kill(err_hook: bool = True): assert ( playbook >> reply() + << http.HttpConnectedHook(connect_flow) + >> reply() << SendData(tctx.client, b"HTTP/1.1 200 Connection established\r\n\r\n") >> DataReceived( tctx.client, b"GET /foo?hello=1 HTTP/1.1\r\nHost: example.com\r\n\r\n" @@ -1621,11 +1660,16 @@ def test_connect_more_newlines(tctx): assert ( playbook - >> DataReceived(tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\n\r\n\r\n") + >> DataReceived( + tctx.client, + b"CONNECT example.com:80 HTTP/1.1\r\nHost: example.com:80\r\n\r\n\r\n", + ) << http.HttpConnectHook(Placeholder()) >> reply() << OpenConnection(server) >> reply(None) + << http.HttpConnectedHook(Placeholder()) + >> reply() << SendData(tctx.client, b"HTTP/1.1 200 Connection established\r\n\r\n") >> DataReceived(tctx.client, b"\x16\x03\x03\x00\xb3\x01\x00\x00\xaf\x03\x03") << layer.NextLayerHook(nl) @@ -1645,12 +1689,13 @@ def require_auth(f: HTTPFlow): assert ( playbook - >> DataReceived(tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\n\r\n") + >> DataReceived( + tctx.client, + b"CONNECT example.com:80 HTTP/1.1\r\nHost: example.com:80\r\n\r\n", + ) << http.HttpConnectHook(flow) >> reply(side_effect=require_auth) - # This isn't ideal - we should probably have a custom CONNECT error hook here. - # See also: test_server_unreachable - << http.HttpResponseHook(flow) + << http.HttpConnectErrorHook(flow) >> reply() << SendData( tctx.client, @@ -1661,6 +1706,7 @@ def require_auth(f: HTTPFlow): >> DataReceived( tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\n" + b"Host: example.com:80\r\n" b"Proxy-Authorization: Basic dGVzdDp0ZXN0\r\n\r\n", ) << http.HttpConnectHook(Placeholder(HTTPFlow)) diff --git a/test/mitmproxy/proxy/layers/http/test_http2.py b/test/mitmproxy/proxy/layers/http/test_http2.py index 40364a7085..4d73dbd9ed 100644 --- a/test/mitmproxy/proxy/layers/http/test_http2.py +++ b/test/mitmproxy/proxy/layers/http/test_http2.py @@ -623,6 +623,60 @@ def test_no_normalization(tctx, normalize): assert flow().response.headers.fields == ((b"Same", b"Here"),) +@pytest.mark.parametrize("stream", ["stream", ""]) +def test_end_stream_via_headers(tctx, stream): + playbook, cff = start_h2_client(tctx) + server = Placeholder(Server) + flow = Placeholder(HTTPFlow) + sff = FrameFactory() + forwarded_request_frames = Placeholder(bytes) + forwarded_response_frames = Placeholder(bytes) + + def enable_streaming(flow: HTTPFlow): + flow.request.stream = bool(stream) + + assert ( + playbook + >> DataReceived( + tctx.client, + cff.build_headers_frame( + example_request_headers, flags=["END_STREAM"] + ).serialize(), + ) + << http.HttpRequestHeadersHook(flow) + >> reply(side_effect=enable_streaming) + << http.HttpRequestHook(flow) + >> reply() + << OpenConnection(server) + >> reply(None, side_effect=make_h2) + << SendData(server, forwarded_request_frames) + >> DataReceived( + server, + sff.build_headers_frame( + example_response_headers, flags=["END_STREAM"] + ).serialize(), + ) + << http.HttpResponseHeadersHook(flow) + >> reply() + << http.HttpResponseHook(flow) + >> reply() + << SendData(tctx.client, forwarded_response_frames) + ) + + frames = decode_frames(forwarded_request_frames()) + assert [type(x) for x in frames] == [ + hyperframe.frame.SettingsFrame, + hyperframe.frame.HeadersFrame, + ] + assert "END_STREAM" in frames[1].flags + + frames = decode_frames(forwarded_response_frames()) + assert [type(x) for x in frames] == [ + hyperframe.frame.HeadersFrame, + ] + assert "END_STREAM" in frames[0].flags + + @pytest.mark.parametrize( "input,pseudo,headers", [ @@ -870,10 +924,10 @@ def test_max_concurrency(tctx): (settings_ack,) = decode_frames(settings_ack_bytes()) (req2,) = decode_frames(req2_bytes()) - assert type(settings) == hyperframe.frame.SettingsFrame - assert type(req1) == hyperframe.frame.HeadersFrame - assert type(settings_ack) == hyperframe.frame.SettingsFrame - assert type(req2) == hyperframe.frame.HeadersFrame + assert type(settings) is hyperframe.frame.SettingsFrame + assert type(req1) is hyperframe.frame.HeadersFrame + assert type(settings_ack) is hyperframe.frame.SettingsFrame + assert type(req2) is hyperframe.frame.HeadersFrame assert req1.stream_id == 1 assert req2.stream_id == 3 diff --git a/test/mitmproxy/proxy/layers/http/test_http3.py b/test/mitmproxy/proxy/layers/http/test_http3.py index 6e6eb88955..2079ebbaf8 100644 --- a/test/mitmproxy/proxy/layers/http/test_http3.py +++ b/test/mitmproxy/proxy/layers/http/test_http3.py @@ -1,4 +1,3 @@ -import collections.abc from collections.abc import Callable from collections.abc import Iterable @@ -14,6 +13,7 @@ from aioquic.h3.connection import parse_settings from aioquic.h3.connection import Setting from aioquic.h3.connection import StreamType +from aioquic.quic.packet import QuicErrorCode from mitmproxy import connection from mitmproxy import version @@ -76,26 +76,6 @@ def __call__(self) -> bytes: return super().__call__() -class MultiPlaybook(tutils.Playbook): - """Playbook that allows multiple events and commands to be registered at once.""" - - def __lshift__(self, c): - if isinstance(c, collections.abc.Iterable): - for c_i in c: - super().__lshift__(c_i) - else: - super().__lshift__(c) - return self - - def __rshift__(self, e): - if isinstance(e, collections.abc.Iterable): - for e_i in e: - super().__rshift__(e_i) - else: - super().__rshift__(e) - return self - - class FrameFactory: """Helper class for generating QUIC stream events and commands.""" @@ -111,7 +91,6 @@ def __init__(self, conn: connection.Connection, is_client: bool) -> None: self.encoder_placeholder: tutils.Placeholder[bytes] | None = None self.peer_stream_id: dict[StreamType, int] = {} self.local_stream_id: dict[StreamType, int] = {} - self.max_push_id: int | None = None def get_default_stream_id(self, stream_type: StreamType, for_local: bool) -> int: if stream_type == StreamType.CONTROL: @@ -158,21 +137,6 @@ def receive_stream_type( end_stream=False, ) - def send_max_push_id(self) -> quic.SendQuicStreamData: - def cb(data: bytes) -> None: - buf = Buffer(data=data) - assert buf.pull_uint_var() == FrameType.MAX_PUSH_ID - buf = Buffer(data=buf.pull_bytes(buf.pull_uint_var())) - self.max_push_id = buf.pull_uint_var() - assert buf.eof() - - return quic.SendQuicStreamData( - connection=self.conn, - stream_id=self.peer_stream_id[StreamType.CONTROL], - data=CallbackPlaceholder(cb), - end_stream=False, - ) - def send_settings(self) -> quic.SendQuicStreamData: assert self.encoder_placeholder is None placeholder = tutils.Placeholder(bytes) @@ -335,27 +299,45 @@ def receive_data( end_stream=end_stream, ) - def send_reset(self, error_code: int, stream_id: int = 0) -> quic.ResetQuicStream: + def send_reset( + self, error_code: ErrorCode, stream_id: int = 0 + ) -> quic.ResetQuicStream: return quic.ResetQuicStream( connection=self.conn, stream_id=stream_id, - error_code=error_code, + error_code=int(error_code), ) def receive_reset( - self, error_code: int, stream_id: int = 0 + self, error_code: ErrorCode, stream_id: int = 0 ) -> quic.QuicStreamReset: return quic.QuicStreamReset( connection=self.conn, stream_id=stream_id, - error_code=error_code, + error_code=int(error_code), + ) + + def send_stop( + self, error_code: ErrorCode, stream_id: int = 0 + ) -> quic.StopSendingQuicStream: + return quic.StopSendingQuicStream( + connection=self.conn, + stream_id=stream_id, + error_code=int(error_code), + ) + + def receive_stop( + self, error_code: ErrorCode, stream_id: int = 0 + ) -> quic.QuicStreamStopSending: + return quic.QuicStreamStopSending( + connection=self.conn, + stream_id=stream_id, + error_code=int(error_code), ) def send_init(self) -> Iterable[quic.SendQuicStreamData]: yield self.send_stream_type(StreamType.CONTROL) yield self.send_settings() - if not self.is_client: - yield self.send_max_push_id() yield self.send_stream_type(StreamType.QPACK_ENCODER) yield self.send_stream_type(StreamType.QPACK_DECODER) @@ -380,12 +362,12 @@ def open_h3_server_conn(): return server -def start_h3_client(tctx: context.Context) -> tuple[tutils.Playbook, FrameFactory]: +def start_h3_proxy(tctx: context.Context) -> tuple[tutils.Playbook, FrameFactory]: tctx.client.alpn = b"h3" tctx.client.transport_protocol = "udp" tctx.server.transport_protocol = "udp" - playbook = MultiPlaybook(layers.HttpLayer(tctx, layers.http.HTTPMode.regular)) + playbook = tutils.Playbook(layers.HttpLayer(tctx, layers.http.HTTPMode.regular)) cff = FrameFactory(conn=tctx.client, is_client=True) assert ( playbook @@ -402,11 +384,11 @@ def make_h3(open_connection: commands.OpenConnection) -> None: def test_ignore_push(tctx: context.Context): - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) def test_fail_without_header(tctx: context.Context): - playbook = MultiPlaybook(layers.http.Http3Server(tctx)) + playbook = tutils.Playbook(layers.http.Http3Server(tctx)) cff = FrameFactory(tctx.client, is_client=True) assert ( playbook @@ -416,12 +398,13 @@ def test_fail_without_header(tctx: context.Context): >> cff.receive_encoder() >> http.ResponseProtocolError(0, "first message", http.status_codes.NO_RESPONSE) << cff.send_reset(ErrorCode.H3_INTERNAL_ERROR) + << cff.send_stop(ErrorCode.H3_INTERNAL_ERROR) ) assert cff.is_done def test_invalid_header(tctx: context.Context): - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) assert ( playbook >> cff.receive_headers( @@ -435,7 +418,7 @@ def test_invalid_header(tctx: context.Context): << cff.send_decoder() # for receive_headers << quic.CloseQuicConnection( tctx.client, - error_code=ErrorCode.H3_GENERAL_PROTOCOL_ERROR, + error_code=ErrorCode.H3_GENERAL_PROTOCOL_ERROR.value, frame_type=None, reason_phrase="Invalid HTTP/3 request headers: Required pseudo header is missing: b':scheme'", ) @@ -452,7 +435,7 @@ def test_invalid_header(tctx: context.Context): def test_simple(tctx: context.Context): - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) flow = tutils.Placeholder(HTTPFlow) server = tutils.Placeholder(connection.Server) sff = FrameFactory(server, is_client=False) @@ -499,7 +482,7 @@ def test_response_trailers( open_h3_server_conn: connection.Server, stream: str, ): - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) tctx.server = open_h3_server_conn sff = FrameFactory(tctx.server, is_client=False) @@ -573,7 +556,7 @@ def test_request_trailers( open_h3_server_conn: connection.Server, stream: str, ): - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) tctx.server = open_h3_server_conn sff = FrameFactory(tctx.server, is_client=False) @@ -629,7 +612,7 @@ def enable_streaming(flow: HTTPFlow): def test_upstream_error(tctx: context.Context): - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) flow = tutils.Placeholder(HTTPFlow) server = tutils.Placeholder(connection.Server) err = tutils.Placeholder(bytes) @@ -680,7 +663,7 @@ def test_http3_client_aborts(tctx: context.Context, stream: str, when: str, how: """ server = tutils.Placeholder(connection.Server) flow = tutils.Placeholder(HTTPFlow) - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) def enable_request_streaming(flow: HTTPFlow): flow.request.stream = True @@ -713,26 +696,28 @@ def enable_response_streaming(flow: HTTPFlow): else: playbook >> quic.QuicConnectionClosed( tctx.client, - error_code=ErrorCode.H3_REQUEST_CANCELLED, + error_code=ErrorCode.H3_REQUEST_CANCELLED.value, frame_type=None, reason_phrase="peer closed connection", ) if stream: playbook << commands.CloseConnection(server) - playbook << http.HttpErrorHook(flow) - playbook >> tutils.reply() + playbook << (error_hook := http.HttpErrorHook(flow)) + if "RST" in how: + playbook << cff.send_reset(ErrorCode.H3_REQUEST_CANCELLED) + playbook >> tutils.reply(to=error_hook) if how == "RST+disconnect": playbook >> quic.QuicConnectionClosed( tctx.client, - error_code=ErrorCode.H3_NO_ERROR, + error_code=ErrorCode.H3_NO_ERROR.value, frame_type=None, reason_phrase="peer closed connection", ) assert playbook assert ( - "stream reset" in flow().error.msg + "stream closed by client" in flow().error.msg or "peer closed connection" in flow().error.msg ) return @@ -770,27 +755,29 @@ def enable_response_streaming(flow: HTTPFlow): else: playbook >> quic.QuicConnectionClosed( tctx.client, - error_code=ErrorCode.H3_REQUEST_CANCELLED, + error_code=ErrorCode.H3_REQUEST_CANCELLED.value, frame_type=None, reason_phrase="peer closed connection", ) playbook << commands.CloseConnection(server) - playbook << http.HttpErrorHook(flow) - playbook >> tutils.reply() + playbook << (error_hook := http.HttpErrorHook(flow)) + if "RST" in how: + playbook << cff.send_reset(ErrorCode.H3_REQUEST_CANCELLED) + playbook >> tutils.reply(to=error_hook) assert playbook if how == "RST+disconnect": playbook >> quic.QuicConnectionClosed( tctx.client, - error_code=ErrorCode.H3_REQUEST_CANCELLED, + error_code=ErrorCode.H3_REQUEST_CANCELLED.value, frame_type=None, reason_phrase="peer closed connection", ) assert playbook if "RST" in how: - assert "stream reset" in flow().error.msg + assert "stream closed by client" in flow().error.msg else: assert "peer closed connection" in flow().error.msg @@ -801,7 +788,7 @@ def test_rst_then_close(tctx): This is slightly different to H2, as QUIC will close the connection immediately. """ - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) flow = tutils.Placeholder(HTTPFlow) server = tutils.Placeholder(connection.Server) err = tutils.Placeholder(str) @@ -820,13 +807,13 @@ def test_rst_then_close(tctx): >> cff.receive_data(b"unexpected data frame") << quic.CloseQuicConnection( tctx.client, - error_code=quic.QuicErrorCode.PROTOCOL_VIOLATION, + error_code=QuicErrorCode.PROTOCOL_VIOLATION.value, frame_type=None, reason_phrase=err, ) >> quic.QuicConnectionClosed( tctx.client, - error_code=quic.QuicErrorCode.PROTOCOL_VIOLATION, + error_code=QuicErrorCode.PROTOCOL_VIOLATION.value, frame_type=None, reason_phrase=err, ) @@ -845,7 +832,7 @@ def test_cancel_then_server_disconnect(tctx: context.Context): - server disconnects - error hook completes. """ - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) flow = tutils.Placeholder(HTTPFlow) server = tutils.Placeholder(connection.Server) assert ( @@ -864,8 +851,9 @@ def test_cancel_then_server_disconnect(tctx: context.Context): # cancel >> cff.receive_reset(error_code=ErrorCode.H3_REQUEST_CANCELLED) << commands.CloseConnection(server) - << http.HttpErrorHook(flow) - >> tutils.reply() + << (err_hook := http.HttpErrorHook(flow)) + << cff.send_reset(ErrorCode.H3_REQUEST_CANCELLED) + >> tutils.reply(to=err_hook) >> events.ConnectionClosed(server) << None ) @@ -882,7 +870,7 @@ def test_cancel_during_response_hook(tctx: context.Context): Given that we have already triggered the response hook, we don't want to trigger the error hook. """ - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) flow = tutils.Placeholder(HTTPFlow) server = tutils.Placeholder(connection.Server) assert ( @@ -905,15 +893,15 @@ def test_cancel_during_response_hook(tctx: context.Context): >> tutils.reply(to=reponse_headers) << (response := http.HttpResponseHook(flow)) >> cff.receive_reset(error_code=ErrorCode.H3_REQUEST_CANCELLED) + << cff.send_reset(ErrorCode.H3_REQUEST_CANCELLED) >> tutils.reply(to=response) - << cff.send_reset(ErrorCode.H3_INTERNAL_ERROR) ) assert cff.is_done def test_stream_concurrency(tctx: context.Context): """Test that we can send an intercepted request with a lower stream id than one that has already been sent.""" - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) flow1 = tutils.Placeholder(HTTPFlow) flow2 = tutils.Placeholder(HTTPFlow) server = tutils.Placeholder(connection.Server) @@ -953,7 +941,7 @@ def test_stream_concurrency(tctx: context.Context): def test_stream_concurrent_get_connection(tctx: context.Context): """Test that an immediate second request for the same domain does not trigger a second connection attempt.""" - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) playbook.hooks = False server = tutils.Placeholder(connection.Server) sff = FrameFactory(server, is_client=False) @@ -979,7 +967,7 @@ def test_stream_concurrent_get_connection(tctx: context.Context): def test_kill_stream(tctx: context.Context): """Test that we can kill individual streams.""" - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) flow1 = tutils.Placeholder(HTTPFlow) flow2 = tutils.Placeholder(HTTPFlow) server = tutils.Placeholder(connection.Server) @@ -1004,6 +992,7 @@ def kill(flow: HTTPFlow): << http.HttpErrorHook(flow2) >> tutils.reply() << cff.send_reset(ErrorCode.H3_INTERNAL_ERROR, stream_id=4) + << cff.send_stop(ErrorCode.H3_INTERNAL_ERROR, stream_id=4) >> tutils.reply(to=request_header1) << http.HttpRequestHook(flow1) >> tutils.reply() @@ -1020,10 +1009,61 @@ def kill(flow: HTTPFlow): assert cff.is_done and sff.is_done +@pytest.mark.parametrize("close_type", ["RESET_STREAM", "STOP_SENDING"]) +def test_receive_stop_sending(tctx: context.Context, close_type: str): + playbook, cff = start_h3_proxy(tctx) + playbook.hooks = False + flow = tutils.Placeholder(HTTPFlow) + server = tutils.Placeholder(connection.Server) + sff = FrameFactory(server, is_client=False) + assert ( + playbook + >> cff.receive_headers(example_request_headers, end_stream=True) + << cff.send_decoder() + << commands.OpenConnection(server) + >> tutils.reply(None, side_effect=make_h3) + << sff.send_init() + << sff.send_headers(example_request_headers, end_stream=True) + >> sff.receive_init() + << sff.send_encoder() + ) + + close1 = cff.receive_reset(ErrorCode.H3_REQUEST_CANCELLED) + close2 = cff.receive_stop(ErrorCode.H3_REQUEST_CANCELLED) + if close_type == "STOP_SENDING": + close1, close2 = close2, close1 + + assert ( + playbook + # Client now closes the stream. + >> close1 + # We shut down the server... + << sff.send_reset(ErrorCode.H3_REQUEST_CANCELLED) + << sff.send_stop(ErrorCode.H3_REQUEST_CANCELLED) + << (err_hook := http.HttpErrorHook(flow)) + # ...and the client stream. + << cff.send_reset(ErrorCode.H3_REQUEST_CANCELLED) + << ( + cff.send_stop(ErrorCode.H3_REQUEST_CANCELLED) + if close_type == "STOP_SENDING" + else None + ) + >> tutils.reply(to=err_hook) + # These don't do anything anymore. + >> close2 + << None + >> sff.receive_reset(ErrorCode.H3_REQUEST_CANCELLED) + << None + >> sff.receive_stop(ErrorCode.H3_REQUEST_CANCELLED) + << None + ) + assert flow().error.msg == "stream closed by client (H3_REQUEST_CANCELLED)" + + class TestClient: def test_no_data_on_closed_stream(self, tctx: context.Context): frame_factory = FrameFactory(tctx.server, is_client=False) - playbook = MultiPlaybook(Http3Client(tctx)) + playbook = tutils.Playbook(Http3Client(tctx)) req = Request.make("GET", "http://example.com/") resp = [(b":status", b"200")] assert ( @@ -1051,15 +1091,16 @@ def test_no_data_on_closed_stream(self, tctx: context.Context): 1, "cancelled", code=http.status_codes.CLIENT_CLOSED_REQUEST ) << frame_factory.send_reset(ErrorCode.H3_REQUEST_CANCELLED) + << frame_factory.send_stop(ErrorCode.H3_REQUEST_CANCELLED) >> frame_factory.receive_data(b"foo") - << quic.StopQuicStream(tctx.server, 0, ErrorCode.H3_REQUEST_CANCELLED) + << None ) # important: no ResponseData event here! assert frame_factory.is_done def test_ignore_wrong_order(self, tctx: context.Context): frame_factory = FrameFactory(tctx.server, is_client=False) - playbook = MultiPlaybook(Http3Client(tctx)) + playbook = tutils.Playbook(Http3Client(tctx)) req = Request.make("GET", "http://example.com/") assert ( playbook @@ -1103,7 +1144,7 @@ def test_ignore_wrong_order(self, tctx: context.Context): def test_early_server_data(tctx: context.Context): - playbook, cff = start_h3_client(tctx) + playbook, cff = start_h3_proxy(tctx) sff = FrameFactory(tctx.server, is_client=False) tctx.server.address = ("example.com", 80) diff --git a/test/mitmproxy/proxy/layers/quic/__init__.py b/test/mitmproxy/proxy/layers/quic/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/mitmproxy/proxy/layers/quic/test__client_hello_parser.py b/test/mitmproxy/proxy/layers/quic/test__client_hello_parser.py new file mode 100644 index 0000000000..82037fb59f --- /dev/null +++ b/test/mitmproxy/proxy/layers/quic/test__client_hello_parser.py @@ -0,0 +1,53 @@ +import pytest +from aioquic.quic.connection import QuicConnection +from aioquic.quic.connection import QuicConnectionError + +from mitmproxy.proxy.layers.quic import _client_hello_parser +from mitmproxy.proxy.layers.quic._client_hello_parser import ( + quic_parse_client_hello_from_datagrams, +) +from test.mitmproxy.proxy.layers.quic.test__stream_layers import client_hello + + +class TestParseClientHello: + def test_input(self): + assert ( + quic_parse_client_hello_from_datagrams([client_hello]).sni == "example.com" + ) + with pytest.raises(ValueError): + quic_parse_client_hello_from_datagrams( + [client_hello[:183] + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00"] + ) + with pytest.raises(ValueError, match="not initial"): + quic_parse_client_hello_from_datagrams( + [ + b"\\s\xd8\xd8\xa5dT\x8bc\xd3\xae\x1c\xb2\x8a7-\x1d\x19j\x85\xb0~\x8c\x80\xa5\x8cY\xac\x0ecK\x7fC2f\xbcm\x1b\xac~" + ] + ) + + def test_invalid(self, monkeypatch): + # XXX: This test is terrible, it should use actual invalid data. + class InvalidClientHello(Exception): + @property + def data(self): + raise EOFError() + + monkeypatch.setattr(_client_hello_parser, "QuicClientHello", InvalidClientHello) + with pytest.raises(ValueError, match="Invalid ClientHello"): + quic_parse_client_hello_from_datagrams([client_hello]) + + def test_connection_error(self, monkeypatch): + def raise_conn_err(self, data, addr, now): + raise QuicConnectionError(0, 0, "Conn err") + + monkeypatch.setattr(QuicConnection, "receive_datagram", raise_conn_err) + with pytest.raises(ValueError, match="Conn err"): + quic_parse_client_hello_from_datagrams([client_hello]) + + def test_no_return(self): + with pytest.raises( + ValueError, match="Invalid ClientHello packet: payload_decrypt_error" + ): + quic_parse_client_hello_from_datagrams( + [client_hello[0:1200] + b"\x00" + client_hello[1200:]] + ) diff --git a/test/mitmproxy/proxy/layers/quic/test__commands.py b/test/mitmproxy/proxy/layers/quic/test__commands.py new file mode 100644 index 0000000000..9ec3e59320 --- /dev/null +++ b/test/mitmproxy/proxy/layers/quic/test__commands.py @@ -0,0 +1,15 @@ +from mitmproxy.proxy.layers.quic._commands import CloseQuicConnection +from mitmproxy.proxy.layers.quic._commands import QuicStreamCommand +from mitmproxy.proxy.layers.quic._commands import ResetQuicStream +from mitmproxy.proxy.layers.quic._commands import SendQuicStreamData +from mitmproxy.proxy.layers.quic._commands import StopSendingQuicStream +from mitmproxy.test.tflow import tclient_conn + + +def test_reprs(): + client = tclient_conn() + assert repr(QuicStreamCommand(client, 42)) + assert repr(SendQuicStreamData(client, 42, b"data")) + assert repr(ResetQuicStream(client, 42, 0xFF)) + assert repr(StopSendingQuicStream(client, 42, 0xFF)) + assert repr(CloseQuicConnection(client, 0xFF, None, "reason")) diff --git a/test/mitmproxy/proxy/layers/quic/test__events.py b/test/mitmproxy/proxy/layers/quic/test__events.py new file mode 100644 index 0000000000..d1d18c034a --- /dev/null +++ b/test/mitmproxy/proxy/layers/quic/test__events.py @@ -0,0 +1,9 @@ +from mitmproxy.proxy.layers.quic._events import QuicConnectionClosed +from mitmproxy.proxy.layers.quic._events import QuicStreamDataReceived +from mitmproxy.test.tflow import tclient_conn + + +def test_reprs(): + client = tclient_conn() + assert repr(QuicStreamDataReceived(client, 42, b"data", end_stream=False)) + assert repr(QuicConnectionClosed(client, 0xFF, None, "reason")) diff --git a/test/mitmproxy/proxy/layers/quic/test__hooks.py b/test/mitmproxy/proxy/layers/quic/test__hooks.py new file mode 100644 index 0000000000..1d660ec9dd --- /dev/null +++ b/test/mitmproxy/proxy/layers/quic/test__hooks.py @@ -0,0 +1,19 @@ +from mitmproxy.options import Options +from mitmproxy.proxy.context import Context +from mitmproxy.proxy.layers.quic._hooks import QuicStartServerHook +from mitmproxy.proxy.layers.quic._hooks import QuicTlsData +from mitmproxy.proxy.layers.quic._hooks import QuicTlsSettings +from mitmproxy.test.tflow import tclient_conn + + +def test_reprs(): + client = tclient_conn() + assert repr( + QuicStartServerHook( + data=QuicTlsData( + conn=client, + context=Context(client, Options()), + settings=QuicTlsSettings(), + ) + ) + ) diff --git a/test/mitmproxy/proxy/layers/quic/test__raw_layers.py b/test/mitmproxy/proxy/layers/quic/test__raw_layers.py new file mode 100644 index 0000000000..4036ce1388 --- /dev/null +++ b/test/mitmproxy/proxy/layers/quic/test__raw_layers.py @@ -0,0 +1,265 @@ +import pytest + +from mitmproxy import connection +from mitmproxy.proxy import commands +from mitmproxy.proxy import context +from mitmproxy.proxy import events +from mitmproxy.proxy import layer +from mitmproxy.proxy import layers +from mitmproxy.proxy import tunnel +from mitmproxy.proxy.layers import tcp +from mitmproxy.proxy.layers import udp +from mitmproxy.proxy.layers.quic._commands import CloseQuicConnection +from mitmproxy.proxy.layers.quic._commands import ResetQuicStream +from mitmproxy.proxy.layers.quic._commands import SendQuicStreamData +from mitmproxy.proxy.layers.quic._commands import StopSendingQuicStream +from mitmproxy.proxy.layers.quic._events import QuicConnectionClosed +from mitmproxy.proxy.layers.quic._events import QuicStreamDataReceived +from mitmproxy.proxy.layers.quic._events import QuicStreamEvent +from mitmproxy.proxy.layers.quic._events import QuicStreamReset +from mitmproxy.proxy.layers.quic._raw_layers import QuicStreamLayer +from mitmproxy.proxy.layers.quic._raw_layers import RawQuicLayer +from mitmproxy.tcp import TCPFlow +from mitmproxy.udp import UDPFlow +from mitmproxy.udp import UDPMessage +from test.mitmproxy.proxy import tutils +from test.mitmproxy.proxy.layers.quic.test__stream_layers import TlsEchoLayer + + +class TestQuicStreamLayer: + def test_force_raw(self, tctx: context.Context): + quic_layer = QuicStreamLayer(tctx, True, 1) + assert isinstance(quic_layer.child_layer, layers.TCPLayer) + quic_layer.child_layer.flow = TCPFlow(tctx.client, tctx.server) + quic_layer.refresh_metadata() + assert quic_layer.child_layer.flow.metadata["quic_is_unidirectional"] is False + assert quic_layer.child_layer.flow.metadata["quic_initiator"] == "server" + assert quic_layer.child_layer.flow.metadata["quic_stream_id_client"] == 1 + assert quic_layer.child_layer.flow.metadata["quic_stream_id_server"] is None + assert quic_layer.stream_id(True) == 1 + assert quic_layer.stream_id(False) is None + + def test_simple(self, tctx: context.Context): + quic_layer = QuicStreamLayer(tctx, False, 2) + assert isinstance(quic_layer.child_layer, layer.NextLayer) + tunnel_layer = tunnel.TunnelLayer(tctx, tctx.client, tctx.server) + quic_layer.child_layer.layer = tunnel_layer + tcp_layer = layers.TCPLayer(tctx) + tunnel_layer.child_layer = tcp_layer + quic_layer.open_server_stream(3) + assert tcp_layer.flow.metadata["quic_is_unidirectional"] is True + assert tcp_layer.flow.metadata["quic_initiator"] == "client" + assert tcp_layer.flow.metadata["quic_stream_id_client"] == 2 + assert tcp_layer.flow.metadata["quic_stream_id_server"] == 3 + assert quic_layer.stream_id(True) == 2 + assert quic_layer.stream_id(False) == 3 + + +class TestRawQuicLayer: + @pytest.mark.parametrize("force_raw", [True, False]) + def test_error(self, tctx: context.Context, force_raw: bool): + quic_layer = RawQuicLayer(tctx, force_raw=force_raw) + assert ( + tutils.Playbook(quic_layer) + << commands.OpenConnection(tctx.server) + >> tutils.reply("failed to open") + << commands.CloseConnection(tctx.client) + ) + assert quic_layer._handle_event == quic_layer.done + + def test_force_raw(self, tctx: context.Context): + quic_layer = RawQuicLayer(tctx, force_raw=True) + assert ( + tutils.Playbook(quic_layer, hooks=False) + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + >> events.DataReceived(tctx.client, b"msg1") + << commands.SendData(tctx.server, b"msg1") + >> events.DataReceived(tctx.server, b"msg2") + << commands.SendData(tctx.client, b"msg2") + >> QuicStreamDataReceived(tctx.client, 0, b"msg3", end_stream=False) + << SendQuicStreamData(tctx.server, 0, b"msg3", end_stream=False) + >> QuicStreamDataReceived(tctx.client, 6, b"msg4", end_stream=False) + << SendQuicStreamData(tctx.server, 2, b"msg4", end_stream=False) + >> QuicStreamDataReceived(tctx.server, 9, b"msg5", end_stream=False) + << SendQuicStreamData(tctx.client, 1, b"msg5", end_stream=False) + >> QuicStreamDataReceived(tctx.client, 0, b"", end_stream=True) + << SendQuicStreamData(tctx.server, 0, b"", end_stream=True) + >> QuicStreamReset(tctx.client, 6, 142) + << ResetQuicStream(tctx.server, 2, 142) + >> QuicConnectionClosed(tctx.client, 42, None, "closed") + << CloseQuicConnection(tctx.server, 42, None, "closed") + >> QuicConnectionClosed(tctx.server, 42, None, "closed") + << None + ) + assert quic_layer._handle_event == quic_layer.done + + def test_msg_inject(self, tctx: context.Context): + udpflow = tutils.Placeholder(UDPFlow) + playbook = tutils.Playbook(RawQuicLayer(tctx)) + assert ( + playbook + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + >> events.DataReceived(tctx.client, b"msg1") + << layer.NextLayerHook(tutils.Placeholder()) + >> tutils.reply_next_layer(udp.UDPLayer) + << udp.UdpStartHook(udpflow) + >> tutils.reply() + << udp.UdpMessageHook(udpflow) + >> tutils.reply() + << commands.SendData(tctx.server, b"msg1") + >> udp.UdpMessageInjected(udpflow, UDPMessage(True, b"msg2")) + << udp.UdpMessageHook(udpflow) + >> tutils.reply() + << commands.SendData(tctx.server, b"msg2") + >> udp.UdpMessageInjected( + UDPFlow(("other", 80), tctx.server), UDPMessage(True, b"msg3") + ) + << udp.UdpMessageHook(udpflow) + >> tutils.reply() + << commands.SendData(tctx.server, b"msg3") + ) + with pytest.raises(AssertionError, match="not associated"): + playbook >> udp.UdpMessageInjected( + UDPFlow(("notfound", 0), ("noexist", 0)), UDPMessage(True, b"msg2") + ) + assert playbook + + def test_reset_with_end_hook(self, tctx: context.Context): + tcpflow = tutils.Placeholder(TCPFlow) + assert ( + tutils.Playbook(RawQuicLayer(tctx)) + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + >> QuicStreamDataReceived(tctx.client, 2, b"msg1", end_stream=False) + << layer.NextLayerHook(tutils.Placeholder()) + >> tutils.reply_next_layer(tcp.TCPLayer) + << tcp.TcpStartHook(tcpflow) + >> tutils.reply() + << tcp.TcpMessageHook(tcpflow) + >> tutils.reply() + << SendQuicStreamData(tctx.server, 2, b"msg1", end_stream=False) + >> QuicStreamReset(tctx.client, 2, 42) + << ResetQuicStream(tctx.server, 2, 42) + << tcp.TcpEndHook(tcpflow) + >> tutils.reply() + ) + + def test_close_with_end_hooks(self, tctx: context.Context): + udpflow = tutils.Placeholder(UDPFlow) + tcpflow = tutils.Placeholder(TCPFlow) + assert ( + tutils.Playbook(RawQuicLayer(tctx)) + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + >> events.DataReceived(tctx.client, b"msg1") + << layer.NextLayerHook(tutils.Placeholder()) + >> tutils.reply_next_layer(udp.UDPLayer) + << udp.UdpStartHook(udpflow) + >> tutils.reply() + << udp.UdpMessageHook(udpflow) + >> tutils.reply() + << commands.SendData(tctx.server, b"msg1") + >> QuicStreamDataReceived(tctx.client, 2, b"msg2", end_stream=False) + << layer.NextLayerHook(tutils.Placeholder()) + >> tutils.reply_next_layer(tcp.TCPLayer) + << tcp.TcpStartHook(tcpflow) + >> tutils.reply() + << tcp.TcpMessageHook(tcpflow) + >> tutils.reply() + << SendQuicStreamData(tctx.server, 2, b"msg2", end_stream=False) + >> QuicConnectionClosed(tctx.client, 42, None, "bye") + << CloseQuicConnection(tctx.server, 42, None, "bye") + << udp.UdpEndHook(udpflow) + << tcp.TcpEndHook(tcpflow) + >> tutils.reply(to=-2) + >> tutils.reply(to=-2) + >> QuicConnectionClosed(tctx.server, 42, None, "bye") + ) + + def test_invalid_stream_event(self, tctx: context.Context): + playbook = tutils.Playbook(RawQuicLayer(tctx)) + assert ( + tutils.Playbook(RawQuicLayer(tctx)) + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + ) + with pytest.raises(AssertionError, match="Unexpected stream event"): + + class InvalidStreamEvent(QuicStreamEvent): + pass + + playbook >> InvalidStreamEvent(tctx.client, 0) + assert playbook + + def test_invalid_event(self, tctx: context.Context): + playbook = tutils.Playbook(RawQuicLayer(tctx)) + assert ( + tutils.Playbook(RawQuicLayer(tctx)) + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + ) + with pytest.raises(AssertionError, match="Unexpected event"): + + class InvalidEvent(events.Event): + pass + + playbook >> InvalidEvent() + assert playbook + + def test_full_close(self, tctx: context.Context): + assert ( + tutils.Playbook(RawQuicLayer(tctx)) + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + >> QuicStreamDataReceived(tctx.client, 0, b"msg1", end_stream=True) + << layer.NextLayerHook(tutils.Placeholder()) + >> tutils.reply_next_layer(lambda ctx: udp.UDPLayer(ctx, ignore=True)) + << SendQuicStreamData(tctx.server, 0, b"msg1", end_stream=False) + << SendQuicStreamData(tctx.server, 0, b"", end_stream=True) + << StopSendingQuicStream(tctx.server, 0, 0) + ) + + def test_open_connection(self, tctx: context.Context): + server = connection.Server(address=("other", 80)) + + def echo_new_server(ctx: context.Context): + echo_layer = TlsEchoLayer(ctx) + echo_layer.context.server = server + return echo_layer + + assert ( + tutils.Playbook(RawQuicLayer(tctx)) + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + >> QuicStreamDataReceived( + tctx.client, 0, b"open-connection", end_stream=False + ) + << layer.NextLayerHook(tutils.Placeholder()) + >> tutils.reply_next_layer(echo_new_server) + << commands.OpenConnection(server) + >> tutils.reply("uhoh") + << SendQuicStreamData( + tctx.client, 0, b"open-connection failed: uhoh", end_stream=False + ) + ) + + def test_invalid_connection_command(self, tctx: context.Context): + playbook = tutils.Playbook(RawQuicLayer(tctx)) + assert ( + playbook + << commands.OpenConnection(tctx.server) + >> tutils.reply(None) + >> QuicStreamDataReceived(tctx.client, 0, b"msg1", end_stream=False) + << layer.NextLayerHook(tutils.Placeholder()) + >> tutils.reply_next_layer(TlsEchoLayer) + << SendQuicStreamData(tctx.client, 0, b"msg1", end_stream=False) + ) + with pytest.raises( + AssertionError, match="Unexpected stream connection command" + ): + playbook >> QuicStreamDataReceived( + tctx.client, 0, b"invalid-command", end_stream=False + ) + assert playbook diff --git a/test/mitmproxy/proxy/layers/test_quic.py b/test/mitmproxy/proxy/layers/quic/test__stream_layers.py similarity index 66% rename from test/mitmproxy/proxy/layers/test_quic.py rename to test/mitmproxy/proxy/layers/quic/test__stream_layers.py index 54ae91f340..8c1c26df06 100644 --- a/test/mitmproxy/proxy/layers/test_quic.py +++ b/test/mitmproxy/proxy/layers/quic/test__stream_layers.py @@ -19,19 +19,31 @@ from mitmproxy.proxy import context from mitmproxy.proxy import events from mitmproxy.proxy import layer -from mitmproxy.proxy import layers -from mitmproxy.proxy import tunnel -from mitmproxy.proxy.layers import quic -from mitmproxy.proxy.layers import tcp from mitmproxy.proxy.layers import tls -from mitmproxy.proxy.layers import udp -from mitmproxy.tcp import TCPFlow -from mitmproxy.udp import UDPFlow -from mitmproxy.udp import UDPMessage +from mitmproxy.proxy.layers.quic._commands import CloseQuicConnection +from mitmproxy.proxy.layers.quic._commands import QuicStreamCommand +from mitmproxy.proxy.layers.quic._commands import ResetQuicStream +from mitmproxy.proxy.layers.quic._commands import SendQuicStreamData +from mitmproxy.proxy.layers.quic._commands import StopSendingQuicStream +from mitmproxy.proxy.layers.quic._events import QuicConnectionClosed +from mitmproxy.proxy.layers.quic._events import QuicStreamDataReceived +from mitmproxy.proxy.layers.quic._events import QuicStreamReset +from mitmproxy.proxy.layers.quic._events import QuicStreamStopSending +from mitmproxy.proxy.layers.quic._hooks import QuicStartClientHook +from mitmproxy.proxy.layers.quic._hooks import QuicStartServerHook +from mitmproxy.proxy.layers.quic._hooks import QuicTlsData +from mitmproxy.proxy.layers.quic._hooks import QuicTlsSettings +from mitmproxy.proxy.layers.quic._stream_layers import ClientQuicLayer +from mitmproxy.proxy.layers.quic._stream_layers import error_code_to_str +from mitmproxy.proxy.layers.quic._stream_layers import is_success_error_code +from mitmproxy.proxy.layers.quic._stream_layers import QuicLayer +from mitmproxy.proxy.layers.quic._stream_layers import QuicSecretsLogger +from mitmproxy.proxy.layers.quic._stream_layers import ServerQuicLayer +from mitmproxy.proxy.layers.quic._stream_layers import tls_settings_to_configuration from mitmproxy.utils import data from test.mitmproxy.proxy import tutils -tlsdata = data.Data(__name__) +tdata = data.Data("test") T = TypeVar("T", bound=layer.Layer) @@ -47,7 +59,7 @@ def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: class TlsEchoLayer(tutils.EchoLayer): err: str | None = None - closed: quic.QuicConnectionClosed | None = None + closed: QuicConnectionClosed | None = None def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: if isinstance(event, events.DataReceived) and event.data == b"open-connection": @@ -64,9 +76,7 @@ def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: isinstance(event, events.DataReceived) and event.data == b"close-connection-error" ): - yield quic.CloseQuicConnection(event.connection, 123, None, "error") - elif isinstance(event, events.DataReceived) and event.data == b"stop-stream": - yield quic.StopQuicStream(event.connection, 24, 123) + yield CloseQuicConnection(event.connection, 123, None, "error") elif ( isinstance(event, events.DataReceived) and event.data == b"invalid-command" ): @@ -80,18 +90,20 @@ class InvalidConnectionCommand(commands.ConnectionCommand): and event.data == b"invalid-stream-command" ): - class InvalidStreamCommand(quic.QuicStreamCommand): + class InvalidStreamCommand(QuicStreamCommand): pass yield InvalidStreamCommand(event.connection, 42) - elif isinstance(event, quic.QuicConnectionClosed): + elif isinstance(event, QuicConnectionClosed): self.closed = event - elif isinstance(event, quic.QuicStreamDataReceived): - yield quic.SendQuicStreamData( + elif isinstance(event, QuicStreamDataReceived): + yield SendQuicStreamData( event.connection, event.stream_id, event.data, event.end_stream ) - elif isinstance(event, quic.QuicStreamReset): - yield quic.ResetQuicStream( + elif isinstance(event, QuicStreamReset): + yield ResetQuicStream(event.connection, event.stream_id, event.error_code) + elif isinstance(event, QuicStreamStopSending): + yield StopSendingQuicStream( event.connection, event.stream_id, event.error_code ) else: @@ -131,306 +143,93 @@ class InvalidStreamCommand(quic.QuicStreamCommand): ) +fragmented_client_hello1 = bytes.fromhex( + "c20000000108d520c3803f5de4d3000044bcb607af28f41aef1616d37bdc7697d73d7963a2d622e7ccddfb4859" + "f369d840f949a29bb19ad7264728eb31eada17a4e1ba666bba67868cf2c30ca4e1d41f67d392c296787a50615a" + "1caf4282f9cc59c98816e1734b57ba4dedf02c225a3f57163bb77703299fafb46d09a4d281eb44f988edd28984" + "04a7161cf7454d8e184f87ae9be1f3bd2c2ae04ba14233ec92960a75a4201bc114070ecfd4c10a4fb0c72749ee" + "b5fa0e52b53dc0da6a485eb8bb467e7a1972c4e1c3a38622857b44eb94d653ee2f2e1fa3bf3f01cacd17b2668a" + "8578e04da4181f3d6ad4031e4f7adec95d015d4f275505ae14fa03154b18c3b838143fac06cb2c8b395effa47c" + "08923e352d1c4beff9e228760f5a80e6214485c7e53efd8d649492aafb3a9c9472335569c2d7971c86f319069e" + "c6ccd13b0b8f517c51fc2e42dc5e7bc3434f306955cf1dc575ea9e18617699045b92b006599afd94abb25018ea" + "f63cfcc247f76b728c4fc4e663dff64b90059d1d27f8ecd63bb548862b88bcd52e0711f222b15c022d214a2cc3" + "93e537e32d149c67aa84692f1a204475a7acceaa0ab5f823ea90af601bdfb7f4036971e1c786fca7fa7e8ab042" + "24307bcc3093886b54e4c9e6b7cb286d6259a8231ffae0f589f687f92232ac5384988631efb70dc85fc594bb3c" + "1c0ceebc08b37d8989da0ae786e30d1278ffddbac47484346afd8439495aa1d392ce76f8ebc8d3d1870a0698ca" + "b133cabbacae924013025e7bce5ac6aaf87684b6409a6a58e8bb294c249a5c7ca9b2961c57dc031485e3a000ec" + "ea4e908cf9f33e86f0fd5d4ca5996b73c273dfda3fe68aa6a385984cb7fd2bf5f69d997580b407d48845215422" + "c3c9fe52e7aa4b4e11c067db3e7c87c55f3b1400f796a4b873b666b7027c33138c1f310f65e20b53bcba019f1e" + "08aee1a89430744c8bd2dd3a788410caa4356099b87cab2463da107a6919af38c159a258ff6693dd71f1941a52" + "01d6a0b2fc52cfab6e0ba2c84c6231bc2a54fe1b6af1641e1168599ea03da913e537880f13128515085fd17b47" + "fe202b82152d1c7df2e66788a2d0e0aab0e6375d368f8064e29912f32d4c509408a642a597bcf39c3e6fe31873" + "e6173067cf3fc65702152e43a9d2cc7262e69550bd3c10e833c3c5ec48878b214426eca9cdc169f59cbc2c93dc" + "94562e05d94761c9f76191b505097dca964d56b9889f904347f6b250f5a1f2bf3c9e9f4370a164a4185e0d83c0" + "96e1799b8d950535cf96eec690fa765e9e74baea45f3157ba8c78158d365acc1a5abb358093cca6afcde287096" + "ba74b4238789ede0947083facfc9bb3129361a283d72fe860c9666877fb263650410ae5af9fd48e9a2214f9f0a" + "39f3b55edca84c836a745f8fc294d176b878fede1e375358d2e63bbbc0632752b19afda03e527b6e9deb32b0a8" + "e617f5396312b7769ccd164e43ba1ada90d97005ab8e4eda57d3a953b5cf5fac9676fc64dd7163bdb6b17f6984" + "f70070f2eadace62317215f240100db10283cd4b7c62f2ba1191c0feee9e6fc6026dcaec12ecb2329221130aac" + "18f08b091f5292e51c0ca35cfefabf9b86d8478f7cc9f2983260e6cec537081684119a02d51e0895d9ee9294cf" + "a6f695173fa816f168751cf1d79730ded3e7e97325d2582a6516436aa165260f576f330535cf28d6f9c26a6f7d" + "dd74b60e702826392ac9f16a1ccdb5" +) + + +fragmented_client_hello2 = bytes.fromhex( + "cd0000000108d520c3803f5de4d3000044bceadc93d1a46ab45f934299ba642a3a4bdac62cf80981105cc546c2" + "96b78fda0acdec8e8cb8a69e4d3446033f3edd0f52fe02d99c841336402b9c2419852414b9bc6b17128b1c198e" + "0f2a709895cddef029b738c7a8bf7917162e5709f7fa4933e6a9db5da418db8794e8458dd699eb31752c402cbf" + "3b6f0d7e6983dba686285a49b4c8724f9653ed4430667a242f4b0613aa37b039226b1c42a1cfaeab40cabbf6be" + "d7d49cbca3a10e8aced1560e44a22073a9432f39e16d177ecf89c4b3807ac748fed84d9811fe91aad76bf85bc8" + "c8b1def2985b8cce6226ce441924418f0c4c6895918e86065a3143dda8afce756c7318b3d861a1f0160d0814ef" + "118389f55198b0c5da4ed6d95a72b6f2a35ffc56bda85753dd146dd6eb29f64b51f7ca7e4e0bf7de82a5041e1f" + "a4dc7303f5b7dc31901185f787876ce81213a587cbe42bdcab63be1c146798641664fecc477b8112109cb317f6" + "f6fe1f3e36c2e843ec875ed8631ac7527817ab928c68a16ae672ca56464556a8c4c700c4f40920a028207911f3" + "2cd2840fce3504ca29f25524b1e9108dbded72ff0364443da17573badc99ad33f6c91baeca3c933258500e7b78" + "347ce76cf893a85f163698edd6209ac5d990f092cc609ff7faa6a0c2e5f57e4154bec72e2441028ad00cdce202" + "a07e0e9696578e0c17c152b2880874cad11631db5210efaf260d18dccecd04987f8ceea7e534c381d9aed5be28" + "8b2086103bd84fd6150037cb0bc1abacd3c2b3f1db213998b4b36e86e46264809fa2757f2b2764c0b94dc222ac" + "674a9f5c183fb40ef52e7b36ed8f3aaf1fe776643d819fb55284387b83f0ad688461ae8612784b36494585caa5" + "f05fb391216bedc23b00e759bebe0cd19f1d514b5faba8a061d36204dd7c4e8daf1150ae8441aadbbeff7735ff" + "613ecb2d1dabf256ffcee5b2ba07f0d2d53c7e98691b261cdadf5fac8ed2985720f7f460a8140fdb094870cc65" + "4656779bbfc095cd5bc666f18e44e86d765004b16a763c330fc165fdb604038067288d56fbd2e6ead2a7352406" + "4f6995a54ef529990239065ccf33ab5fa3e56ec2ff15b6981bab32658c5d4184407865f3a0e7c37d8d53ac4850" + "cfdb16887e04eea4284517b2141c1824babae24207ba14e91eb6a30735f33f664d7fefde94d582c06dd26922a6" + "6e4657c144ee9f99b7985ba1fd7dceb700cecdcb8950a57fc3b239709e84a4616d8e0f7865025b37d27e5cc7c2" + "b24b02745a89e12315ff4c4e87ea0d4ff90018f4243de3668b22547ba3a147540582b28152ad9412f0c2aea0c1" + "c0bf71c4176fed4c1d96853ef1d5db80ce4ba66d67c6998c052ebb2cf05511c54d233c24c2f9ed1ea14c305eba" + "9aed02ad0f1c48772646bfc4edc3f735cd3c16c885e1c54918e0070e1bcc68d835097fe43183e3ef26ab3d1993" + "dca6960b6ca0ffb1b90417114e55364211c1bd9688adfbb77ebfd7b7ffe47c45f3813390aeb5020fb63c018641" + "5a260ae26fab479e170843936d8e786120afa6edacecb32abfbe180237b0684507636fe221b2b980683a9f3610" + "8619c5ab4e271dd450d855f0085814750347da051a903bfa251b395cdc59356c68a7dae062e770c37f4d14f8b9" + "dd989248e7449e9b581ef9925d85e06372dd61bcbde872791e71855a5aa0c734d387731dde31d02500e1cd5f51" + "954f0e999398e6b0762bf6bb6bef9a" +) + + def test_error_code_to_str(): - assert quic.error_code_to_str(0x6) == "FINAL_SIZE_ERROR" - assert quic.error_code_to_str(0x104) == "H3_CLOSED_CRITICAL_STREAM" - assert quic.error_code_to_str(0xDEAD) == f"unknown error (0xdead)" + assert error_code_to_str(0x6) == "FINAL_SIZE_ERROR" + assert error_code_to_str(0x104) == "H3_CLOSED_CRITICAL_STREAM" + assert error_code_to_str(0xDEAD) == f"unknown error (0xdead)" def test_is_success_error_code(): - assert quic.is_success_error_code(0x0) - assert not quic.is_success_error_code(0x6) - assert quic.is_success_error_code(0x100) - assert not quic.is_success_error_code(0x104) - assert not quic.is_success_error_code(0xDEAD) + assert is_success_error_code(0x0) + assert not is_success_error_code(0x6) + assert is_success_error_code(0x100) + assert not is_success_error_code(0x104) + assert not is_success_error_code(0xDEAD) @pytest.mark.parametrize("value", ["s1 s2\n", "s1 s2"]) def test_secrets_logger(value: str): logger = MagicMock() - quic_logger = quic.QuicSecretsLogger(logger) + quic_logger = QuicSecretsLogger(logger) assert quic_logger.write(value) == 6 quic_logger.flush() logger.assert_called_once_with(None, b"s1 s2") -class TestParseClientHello: - def test_input(self): - assert quic.quic_parse_client_hello(client_hello).sni == "example.com" - with pytest.raises(ValueError): - quic.quic_parse_client_hello( - client_hello[:183] + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00" - ) - with pytest.raises(ValueError, match="not initial"): - quic.quic_parse_client_hello( - b"\\s\xd8\xd8\xa5dT\x8bc\xd3\xae\x1c\xb2\x8a7-\x1d\x19j\x85\xb0~\x8c\x80\xa5\x8cY\xac\x0ecK\x7fC2f\xbcm\x1b\xac~" - ) - - def test_invalid(self, monkeypatch): - class InvalidClientHello(Exception): - @property - def data(self): - raise EOFError() - - monkeypatch.setattr(quic, "QuicClientHello", InvalidClientHello) - with pytest.raises(ValueError, match="Invalid ClientHello"): - quic.quic_parse_client_hello(client_hello) - - def test_connection_error(self, monkeypatch): - def raise_conn_err(self, data, addr, now): - raise quic.QuicConnectionError(0, 0, "Conn err") - - monkeypatch.setattr(QuicConnection, "receive_datagram", raise_conn_err) - with pytest.raises(ValueError, match="Conn err"): - quic.quic_parse_client_hello(client_hello) - - def test_no_return(self): - with pytest.raises(ValueError, match="No ClientHello"): - quic.quic_parse_client_hello( - client_hello[0:1200] + b"\x00" + client_hello[1200:] - ) - - -class TestQuicStreamLayer: - def test_ignored(self, tctx: context.Context): - quic_layer = quic.QuicStreamLayer(tctx, True, 1) - assert isinstance(quic_layer.child_layer, layers.TCPLayer) - assert not quic_layer.child_layer.flow - quic_layer.child_layer.flow = TCPFlow(tctx.client, tctx.server) - quic_layer.refresh_metadata() - assert quic_layer.child_layer.flow.metadata["quic_is_unidirectional"] is False - assert quic_layer.child_layer.flow.metadata["quic_initiator"] == "server" - assert quic_layer.child_layer.flow.metadata["quic_stream_id_client"] == 1 - assert quic_layer.child_layer.flow.metadata["quic_stream_id_server"] is None - assert quic_layer.stream_id(True) == 1 - assert quic_layer.stream_id(False) is None - - def test_simple(self, tctx: context.Context): - quic_layer = quic.QuicStreamLayer(tctx, False, 2) - assert isinstance(quic_layer.child_layer, layer.NextLayer) - tunnel_layer = tunnel.TunnelLayer(tctx, tctx.client, tctx.server) - quic_layer.child_layer.layer = tunnel_layer - tcp_layer = layers.TCPLayer(tctx) - tunnel_layer.child_layer = tcp_layer - quic_layer.open_server_stream(3) - assert tcp_layer.flow.metadata["quic_is_unidirectional"] is True - assert tcp_layer.flow.metadata["quic_initiator"] == "client" - assert tcp_layer.flow.metadata["quic_stream_id_client"] == 2 - assert tcp_layer.flow.metadata["quic_stream_id_server"] == 3 - assert quic_layer.stream_id(True) == 2 - assert quic_layer.stream_id(False) == 3 - - -class TestRawQuicLayer: - @pytest.mark.parametrize("ignore", [True, False]) - def test_error(self, tctx: context.Context, ignore: bool): - quic_layer = quic.RawQuicLayer(tctx, ignore=ignore) - assert ( - tutils.Playbook(quic_layer) - << commands.OpenConnection(tctx.server) - >> tutils.reply("failed to open") - << commands.CloseConnection(tctx.client) - ) - assert quic_layer._handle_event == quic_layer.done - - def test_ignored(self, tctx: context.Context): - quic_layer = quic.RawQuicLayer(tctx, ignore=True) - assert ( - tutils.Playbook(quic_layer) - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - >> events.DataReceived(tctx.client, b"msg1") - << commands.SendData(tctx.server, b"msg1") - >> events.DataReceived(tctx.server, b"msg2") - << commands.SendData(tctx.client, b"msg2") - >> quic.QuicStreamDataReceived(tctx.client, 0, b"msg3", end_stream=False) - << quic.SendQuicStreamData(tctx.server, 0, b"msg3", end_stream=False) - >> quic.QuicStreamDataReceived(tctx.client, 6, b"msg4", end_stream=False) - << quic.SendQuicStreamData(tctx.server, 2, b"msg4", end_stream=False) - >> quic.QuicStreamDataReceived(tctx.server, 9, b"msg5", end_stream=False) - << quic.SendQuicStreamData(tctx.client, 1, b"msg5", end_stream=False) - >> quic.QuicStreamDataReceived(tctx.client, 0, b"", end_stream=True) - << quic.SendQuicStreamData(tctx.server, 0, b"", end_stream=True) - >> quic.QuicStreamReset(tctx.client, 6, 142) - << quic.ResetQuicStream(tctx.server, 2, 142) - >> quic.QuicConnectionClosed(tctx.client, 42, None, "closed") - << quic.CloseQuicConnection(tctx.server, 42, None, "closed") - >> quic.QuicConnectionClosed(tctx.server, 42, None, "closed") - << None - ) - assert quic_layer._handle_event == quic_layer.done - - def test_msg_inject(self, tctx: context.Context): - udpflow = tutils.Placeholder(UDPFlow) - playbook = tutils.Playbook(quic.RawQuicLayer(tctx)) - assert ( - playbook - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - >> events.DataReceived(tctx.client, b"msg1") - << layer.NextLayerHook(tutils.Placeholder()) - >> tutils.reply_next_layer(udp.UDPLayer) - << udp.UdpStartHook(udpflow) - >> tutils.reply() - << udp.UdpMessageHook(udpflow) - >> tutils.reply() - << commands.SendData(tctx.server, b"msg1") - >> udp.UdpMessageInjected(udpflow, UDPMessage(True, b"msg2")) - << udp.UdpMessageHook(udpflow) - >> tutils.reply() - << commands.SendData(tctx.server, b"msg2") - >> udp.UdpMessageInjected( - UDPFlow(("other", 80), tctx.server), UDPMessage(True, b"msg3") - ) - << udp.UdpMessageHook(udpflow) - >> tutils.reply() - << commands.SendData(tctx.server, b"msg3") - ) - with pytest.raises(AssertionError, match="not associated"): - playbook >> udp.UdpMessageInjected( - UDPFlow(("notfound", 0), ("noexist", 0)), UDPMessage(True, b"msg2") - ) - assert playbook - - def test_reset_with_end_hook(self, tctx: context.Context): - tcpflow = tutils.Placeholder(TCPFlow) - assert ( - tutils.Playbook(quic.RawQuicLayer(tctx)) - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - >> quic.QuicStreamDataReceived(tctx.client, 2, b"msg1", end_stream=False) - << layer.NextLayerHook(tutils.Placeholder()) - >> tutils.reply_next_layer(tcp.TCPLayer) - << tcp.TcpStartHook(tcpflow) - >> tutils.reply() - << tcp.TcpMessageHook(tcpflow) - >> tutils.reply() - << quic.SendQuicStreamData(tctx.server, 2, b"msg1", end_stream=False) - >> quic.QuicStreamReset(tctx.client, 2, 42) - << quic.ResetQuicStream(tctx.server, 2, 42) - << tcp.TcpEndHook(tcpflow) - >> tutils.reply() - ) - - def test_close_with_end_hooks(self, tctx: context.Context): - udpflow = tutils.Placeholder(UDPFlow) - tcpflow = tutils.Placeholder(TCPFlow) - assert ( - tutils.Playbook(quic.RawQuicLayer(tctx)) - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - >> events.DataReceived(tctx.client, b"msg1") - << layer.NextLayerHook(tutils.Placeholder()) - >> tutils.reply_next_layer(udp.UDPLayer) - << udp.UdpStartHook(udpflow) - >> tutils.reply() - << udp.UdpMessageHook(udpflow) - >> tutils.reply() - << commands.SendData(tctx.server, b"msg1") - >> quic.QuicStreamDataReceived(tctx.client, 2, b"msg2", end_stream=False) - << layer.NextLayerHook(tutils.Placeholder()) - >> tutils.reply_next_layer(tcp.TCPLayer) - << tcp.TcpStartHook(tcpflow) - >> tutils.reply() - << tcp.TcpMessageHook(tcpflow) - >> tutils.reply() - << quic.SendQuicStreamData(tctx.server, 2, b"msg2", end_stream=False) - >> quic.QuicConnectionClosed(tctx.client, 42, None, "bye") - << quic.CloseQuicConnection(tctx.server, 42, None, "bye") - << tcp.TcpEndHook(tcpflow) - >> tutils.reply() - >> quic.QuicConnectionClosed(tctx.server, 42, None, "bye") - << udp.UdpEndHook(udpflow) - >> tutils.reply() - ) - - def test_invalid_stream_event(self, tctx: context.Context): - playbook = tutils.Playbook(quic.RawQuicLayer(tctx)) - assert ( - tutils.Playbook(quic.RawQuicLayer(tctx)) - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - ) - with pytest.raises(AssertionError, match="Unexpected stream event"): - - class InvalidStreamEvent(quic.QuicStreamEvent): - pass - - playbook >> InvalidStreamEvent(tctx.client, 0) - assert playbook - - def test_invalid_event(self, tctx: context.Context): - playbook = tutils.Playbook(quic.RawQuicLayer(tctx)) - assert ( - tutils.Playbook(quic.RawQuicLayer(tctx)) - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - ) - with pytest.raises(AssertionError, match="Unexpected event"): - - class InvalidEvent(events.Event): - pass - - playbook >> InvalidEvent() - assert playbook - - def test_full_close(self, tctx: context.Context): - assert ( - tutils.Playbook(quic.RawQuicLayer(tctx)) - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - >> quic.QuicStreamDataReceived(tctx.client, 0, b"msg1", end_stream=True) - << layer.NextLayerHook(tutils.Placeholder()) - >> tutils.reply_next_layer(lambda ctx: udp.UDPLayer(ctx, ignore=True)) - << quic.SendQuicStreamData(tctx.server, 0, b"msg1", end_stream=False) - << quic.SendQuicStreamData(tctx.server, 0, b"", end_stream=True) - << quic.StopQuicStream(tctx.server, 0, 0) - ) - - def test_open_connection(self, tctx: context.Context): - server = connection.Server(address=("other", 80)) - - def echo_new_server(ctx: context.Context): - echo_layer = TlsEchoLayer(ctx) - echo_layer.context.server = server - return echo_layer - - assert ( - tutils.Playbook(quic.RawQuicLayer(tctx)) - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - >> quic.QuicStreamDataReceived( - tctx.client, 0, b"open-connection", end_stream=False - ) - << layer.NextLayerHook(tutils.Placeholder()) - >> tutils.reply_next_layer(echo_new_server) - << commands.OpenConnection(server) - >> tutils.reply("uhoh") - << quic.SendQuicStreamData( - tctx.client, 0, b"open-connection failed: uhoh", end_stream=False - ) - ) - - def test_invalid_connection_command(self, tctx: context.Context): - playbook = tutils.Playbook(quic.RawQuicLayer(tctx)) - assert ( - playbook - << commands.OpenConnection(tctx.server) - >> tutils.reply(None) - >> quic.QuicStreamDataReceived(tctx.client, 0, b"msg1", end_stream=False) - << layer.NextLayerHook(tutils.Placeholder()) - >> tutils.reply_next_layer(TlsEchoLayer) - << quic.SendQuicStreamData(tctx.client, 0, b"msg1", end_stream=False) - ) - with pytest.raises( - AssertionError, match="Unexpected stream connection command" - ): - playbook >> quic.QuicStreamDataReceived( - tctx.client, 0, b"invalid-command", end_stream=False - ) - assert playbook - - class MockQuic(QuicConnection): def __init__(self, event) -> None: super().__init__(configuration=QuicConfiguration(is_client=True)) @@ -454,7 +253,7 @@ def make_mock_quic( established: bool = True, ) -> tuple[tutils.Playbook, MockQuic]: tctx.client.state = connection.ConnectionState.CLOSED - quic_layer = quic.QuicLayer(tctx, tctx.client, time=lambda: 0) + quic_layer = QuicLayer(tctx, tctx.client, time=lambda: 0) quic_layer.child_layer = TlsEchoLayer(tctx) mock = MockQuic(event) quic_layer.quic = mock @@ -506,7 +305,7 @@ def test_close_error(self, tctx: context.Context): assert ( playbook >> events.DataReceived(tctx.client, b"") - << quic.CloseQuicConnection(tctx.client, 123, None, "error") + << CloseQuicConnection(tctx.client, 123, None, "error") ) assert conn._close_event assert conn._close_event.error_code == 123 @@ -536,9 +335,7 @@ def test_stream_reset(self, tctx: context.Context): assert conn._streams[42].sender._reset_error_code == 123 def test_stream_stop(self, tctx: context.Context): - playbook, conn = make_mock_quic( - tctx, quic_events.DatagramFrameReceived(b"stop-stream") - ) + playbook, conn = make_mock_quic(tctx, quic_events.StopSendingReceived(123, 24)) assert 24 not in conn._streams conn._get_or_create_stream_for_send(24) assert playbook >> events.DataReceived(tctx.client, b"") @@ -555,7 +352,7 @@ def __init__( alpn: list[str] | None = None, sni: str | None = "example.mitmproxy.org", version: int | None = None, - settings: quic.QuicTlsSettings | None = None, + settings: QuicTlsSettings | None = None, ): if settings is None: self.ctx = QuicConfiguration( @@ -565,8 +362,8 @@ def __init__( self.ctx.verify_mode = ssl.CERT_OPTIONAL self.ctx.load_verify_locations( - cafile=tlsdata.path( - "../../net/data/verificationcerts/trusted-root.crt" + cafile=tdata.path( + "mitmproxy/net/data/verificationcerts/trusted-root.crt" ), ) @@ -578,11 +375,11 @@ def __init__( else: filename = "trusted-leaf" self.ctx.load_cert_chain( - certfile=tlsdata.path( - f"../../net/data/verificationcerts/{filename}.crt" + certfile=tdata.path( + f"mitmproxy/net/data/verificationcerts/{filename}.crt" ), - keyfile=tlsdata.path( - f"../../net/data/verificationcerts/{filename}.key" + keyfile=tdata.path( + f"mitmproxy/net/data/verificationcerts/{filename}.key" ), ) @@ -593,7 +390,7 @@ def __init__( else: assert alpn is None assert version is None - self.ctx = quic.tls_settings_to_configuration( + self.ctx = tls_settings_to_configuration( settings=settings, is_client=not server_side, server_name=sni, @@ -605,7 +402,7 @@ def __init__( if not server_side: self.quic.connect(self.address, now=self.now) - def write(self, buf: bytes) -> int: + def write(self, buf: bytes): self.now = self.now + 0.1 if self.quic is None: quic_buf = QuicBuffer(data=buf) @@ -695,13 +492,13 @@ def reply_tls_start_client(alpn: str | None = None, *args, **kwargs) -> tutils.r Helper function to simplify the syntax for quic_start_client hooks. """ - def make_client_conn(tls_start: quic.QuicTlsData) -> None: + def make_client_conn(tls_start: QuicTlsData) -> None: config = QuicConfiguration() config.load_cert_chain( - tlsdata.path("../../net/data/verificationcerts/trusted-leaf.crt"), - tlsdata.path("../../net/data/verificationcerts/trusted-leaf.key"), + tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.crt"), + tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.key"), ) - tls_start.settings = quic.QuicTlsSettings( + tls_start.settings = QuicTlsSettings( certificate=config.certificate, certificate_chain=config.certificate_chain, certificate_private_key=config.private_key, @@ -717,9 +514,9 @@ def reply_tls_start_server(alpn: str | None = None, *args, **kwargs) -> tutils.r Helper function to simplify the syntax for quic_start_server hooks. """ - def make_server_conn(tls_start: quic.QuicTlsData) -> None: - tls_start.settings = quic.QuicTlsSettings( - ca_file=tlsdata.path("../../net/data/verificationcerts/trusted-root.crt"), + def make_server_conn(tls_start: QuicTlsData) -> None: + tls_start.settings = QuicTlsSettings( + ca_file=tdata.path("mitmproxy/net/data/verificationcerts/trusted-root.crt"), verify_mode=ssl.CERT_REQUIRED, ) if alpn is not None: @@ -728,13 +525,13 @@ def make_server_conn(tls_start: quic.QuicTlsData) -> None: return tutils.reply(*args, side_effect=make_server_conn, **kwargs) -class TestServerTLS: +class TestServerQuic: def test_repr(self, tctx: context.Context): - assert repr(quic.ServerQuicLayer(tctx, time=lambda: 0)) + assert repr(ServerQuicLayer(tctx, time=lambda: 0)) def test_not_connected(self, tctx: context.Context): """Test that we don't do anything if no server connection exists.""" - layer = quic.ServerQuicLayer(tctx, time=lambda: 0) + layer = ServerQuicLayer(tctx, time=lambda: 0) layer.child_layer = TlsEchoLayer(tctx) assert ( @@ -746,7 +543,7 @@ def test_not_connected(self, tctx: context.Context): def test_simple(self, tctx: context.Context): tssl = SSLTest(server_side=True) - playbook = tutils.Playbook(quic.ServerQuicLayer(tctx, time=lambda: tssl.now)) + playbook = tutils.Playbook(ServerQuicLayer(tctx, time=lambda: tssl.now)) tctx.server.address = ("example.mitmproxy.org", 443) tctx.server.state = connection.ConnectionState.OPEN tctx.server.sni = "example.mitmproxy.org" @@ -755,7 +552,7 @@ def test_simple(self, tctx: context.Context): data = tutils.Placeholder(bytes) assert ( playbook - << quic.QuicStartServerHook(tutils.Placeholder()) + << QuicStartServerHook(tutils.Placeholder()) >> reply_tls_start_server() << commands.SendData(tctx.server, data) << commands.RequestWakeup(0.2) @@ -789,7 +586,7 @@ def test_simple(self, tctx: context.Context): tssl.now = tssl.now + 60 assert ( playbook - >> events.Wakeup(playbook.actual[4]) + >> tutils.reply(to=commands.RequestWakeup) << commands.CloseConnection(tctx.server) >> events.ConnectionClosed(tctx.server) << None @@ -802,7 +599,7 @@ def test_untrusted_cert(self, tctx: context.Context): """If the certificate is not trusted, we should fail.""" tssl = SSLTest(server_side=True) - playbook = tutils.Playbook(quic.ServerQuicLayer(tctx, time=lambda: tssl.now)) + playbook = tutils.Playbook(ServerQuicLayer(tctx, time=lambda: tssl.now)) tctx.server.address = ("wrong.host.mitmproxy.org", 443) tctx.server.sni = "wrong.host.mitmproxy.org" @@ -815,7 +612,7 @@ def test_untrusted_cert(self, tctx: context.Context): >> events.DataReceived(tctx.client, b"open-connection") << commands.OpenConnection(tctx.server) >> tutils.reply(None) - << quic.QuicStartServerHook(tutils.Placeholder()) + << QuicStartServerHook(tutils.Placeholder()) >> reply_tls_start_server() << commands.SendData(tctx.server, data) << commands.RequestWakeup(0.2) @@ -835,12 +632,14 @@ def test_untrusted_cert(self, tctx: context.Context): tssl.write(data()) tssl.now = tssl.now + 60 - tls_hook_data = tutils.Placeholder(quic.QuicTlsData) + tls_hook_data = tutils.Placeholder(QuicTlsData) assert ( playbook - >> events.Wakeup(playbook.actual[9]) + >> tutils.reply(to=commands.RequestWakeup) << commands.Log( - "Server QUIC handshake failed. Certificate does not match hostname 'wrong.host.mitmproxy.org'", + tutils.StrMatching( + "Server QUIC handshake failed. hostname 'wrong.host.mitmproxy.org' doesn't match" + ), WARNING, ) << tls.TlsFailedServerHook(tls_hook_data) @@ -848,19 +647,20 @@ def test_untrusted_cert(self, tctx: context.Context): << commands.CloseConnection(tctx.server) << commands.SendData( tctx.client, - b"open-connection failed: Certificate does not match hostname 'wrong.host.mitmproxy.org'", + tutils.BytesMatching( + b"open-connection failed: hostname 'wrong.host.mitmproxy.org' doesn't match" + ), ) ) - assert ( - tls_hook_data().conn.error - == "Certificate does not match hostname 'wrong.host.mitmproxy.org'" + assert tls_hook_data().conn.error.startswith( + "hostname 'wrong.host.mitmproxy.org' doesn't match" ) assert not tctx.server.tls_established def make_client_tls_layer( tctx: context.Context, no_server: bool = False, **kwargs -) -> tuple[tutils.Playbook, quic.ClientQuicLayer, SSLTest]: +) -> tuple[tutils.Playbook, ClientQuicLayer, SSLTest]: tssl_client = SSLTest(**kwargs) # This is a bit contrived as the client layer expects a server layer as parent. @@ -868,9 +668,9 @@ def make_client_tls_layer( server_layer = ( DummyLayer(tctx) if no_server - else quic.ServerQuicLayer(tctx, time=lambda: tssl_client.now) + else ServerQuicLayer(tctx, time=lambda: tssl_client.now) ) - client_layer = quic.ClientQuicLayer(tctx, time=lambda: tssl_client.now) + client_layer = ClientQuicLayer(tctx, time=lambda: tssl_client.now) server_layer.child_layer = client_layer playbook = tutils.Playbook(server_layer) @@ -887,12 +687,12 @@ def make_client_tls_layer( return playbook, client_layer, tssl_client -class TestClientTLS: +class TestClientQuic: def test_http3_disabled(self, tctx: context.Context): """Test that we swallow QUIC packets if QUIC and HTTP/3 are disabled.""" tctx.options.http3 = False assert ( - tutils.Playbook(quic.ClientQuicLayer(tctx, time=time.time), logs=True) + tutils.Playbook(ClientQuicLayer(tctx, time=time.time), logs=True) >> events.DataReceived(tctx.client, client_hello) << commands.Log( "Swallowing QUIC handshake because HTTP/3 is disabled.", DEBUG @@ -901,7 +701,7 @@ def test_http3_disabled(self, tctx: context.Context): ) def test_client_only(self, tctx: context.Context): - """Test TLS with client only""" + """Test QUIC with client only""" playbook, client_layer, tssl_client = make_client_tls_layer(tctx) client_layer.debug = " " assert not tctx.client.tls_established @@ -913,7 +713,7 @@ def test_client_only(self, tctx: context.Context): >> events.DataReceived(tctx.client, tssl_client.read()) << tls.TlsClienthelloHook(tutils.Placeholder()) >> tutils.reply() - << quic.QuicStartClientHook(tutils.Placeholder()) + << QuicStartClientHook(tutils.Placeholder()) >> reply_tls_start_client() << commands.SendData(tctx.client, data) << commands.RequestWakeup(tutils.Placeholder()) @@ -939,9 +739,11 @@ def test_client_only(self, tctx: context.Context): tssl_client.now = tssl_client.now + 60 assert ( playbook - >> events.Wakeup(playbook.actual[16]) + >> tutils.reply(to=commands.RequestWakeup) << commands.Log( - " >> Wakeup(command=RequestWakeup({'delay': 0.20000000000000004}))", + tutils.StrMatching( + r" >> Wakeup\(command=RequestWakeup\({'delay': [.\d]+}\)\)" + ), DEBUG, ) << commands.Log( @@ -981,7 +783,7 @@ def require_server_conn(client_hello: tls.ClientHelloData) -> None: playbook >> tutils.reply(None) assert ( playbook - << quic.QuicStartServerHook(tutils.Placeholder()) + << QuicStartServerHook(tutils.Placeholder()) >> reply_tls_start_server(alpn="quux") << commands.SendData(tctx.server, data) << commands.RequestWakeup(tutils.Placeholder()) @@ -999,7 +801,7 @@ def require_server_conn(client_hello: tls.ClientHelloData) -> None: >> tutils.reply() << commands.SendData(tctx.server, data) << commands.RequestWakeup(tutils.Placeholder()) - << quic.QuicStartClientHook(tutils.Placeholder()) + << QuicStartClientHook(tutils.Placeholder()) ) tssl_server.write(data()) assert tctx.server.tls_established @@ -1061,6 +863,33 @@ def make_passthrough(client_hello: tls.ClientHelloData) -> None: << commands.SendData(tctx.client, b"ServerHello") ) + @pytest.mark.parametrize( + "fragments", + [ + [fragmented_client_hello1, fragmented_client_hello2], + [fragmented_client_hello2, fragmented_client_hello1], + ], + ) + def test_fragmented_client_hello( + self, tctx: context.Context, fragments: list[bytes] + ): + client_layer = ClientQuicLayer(tctx, time=time.time) + playbook = tutils.Playbook(client_layer) + + assert not tctx.client.sni + + assert ( + playbook + >> events.Start() + >> events.DataReceived(tctx.client, fragments[0]) + >> events.DataReceived(tctx.client, fragments[1]) + << tls.TlsClienthelloHook(tutils.Placeholder()) + >> tutils.reply() + << QuicStartClientHook(tutils.Placeholder()) + ) + + assert tctx.client.sni == "localhost" + @pytest.mark.parametrize( "data,err", [ @@ -1073,7 +902,7 @@ def test_cannot_parse_clienthello( ): """Test the scenario where we cannot parse the ClientHello""" playbook, client_layer, tssl_client = make_client_tls_layer(tctx) - tls_hook_data = tutils.Placeholder(quic.QuicTlsData) + tls_hook_data = tutils.Placeholder(QuicTlsData) assert ( playbook @@ -1116,7 +945,7 @@ def test_mitmproxy_ca_is_untrusted(self, tctx: context.Context): >> events.DataReceived(tctx.client, tssl_client.read()) << tls.TlsClienthelloHook(tutils.Placeholder()) >> tutils.reply() - << quic.QuicStartClientHook(tutils.Placeholder()) + << QuicStartClientHook(tutils.Placeholder()) >> reply_tls_start_client() << commands.SendData(tctx.client, data) << commands.RequestWakeup(tutils.Placeholder()) @@ -1125,15 +954,17 @@ def test_mitmproxy_ca_is_untrusted(self, tctx: context.Context): assert not tssl_client.handshake_completed() # Finish Handshake - tls_hook_data = tutils.Placeholder(quic.QuicTlsData) + tls_hook_data = tutils.Placeholder(QuicTlsData) playbook >> events.DataReceived(tctx.client, tssl_client.read()) assert playbook tssl_client.now = tssl_client.now + 60 assert ( playbook - >> events.Wakeup(playbook.actual[7]) + >> tutils.reply(to=commands.RequestWakeup) << commands.Log( - "Client QUIC handshake failed. Certificate does not match hostname 'wrong.host.mitmproxy.org'", + tutils.StrMatching( + "Client QUIC handshake failed. hostname 'wrong.host.mitmproxy.org' doesn't match" + ), WARNING, ) << tls.TlsFailedClientHook(tls_hook_data) @@ -1163,7 +994,7 @@ def require_server_conn(client_hello: tls.ClientHelloData) -> None: f"If you plan to redirect requests away from this server, " f"consider setting `connection_strategy` to `lazy` to suppress early connections." ) - << quic.QuicStartClientHook(tutils.Placeholder()) + << QuicStartClientHook(tutils.Placeholder()) ) tctx.client.state = connection.ConnectionState.CLOSED assert ( @@ -1196,11 +1027,15 @@ def require_server_conn(client_hello: tls.ClientHelloData) -> None: f"If you plan to redirect requests away from this server, " f"consider setting `connection_strategy` to `lazy` to suppress early connections." ) - << quic.QuicStartClientHook(tutils.Placeholder()) + << QuicStartClientHook(tutils.Placeholder()) ) def test_version_negotiation(self, tctx: context.Context): - playbook, client_layer, tssl_client = make_client_tls_layer(tctx, version=0) + # To trigger a version negotiation, use one of the reserved 0x?A?A?A?A versions. + # https://datatracker.ietf.org/doc/html/rfc9000#section-15 + playbook, client_layer, tssl_client = make_client_tls_layer( + tctx, version=0x1A2A3A4A + ) assert ( playbook >> events.DataReceived(tctx.client, tssl_client.read()) @@ -1237,7 +1072,31 @@ def test_invalid_clienthello(self, tctx: context.Context): playbook >> events.DataReceived(tctx.client, data) << commands.Log( - f"Client QUIC handshake failed. Cannot parse ClientHello: No ClientHello returned. ({data.hex()})", + f"Client QUIC handshake failed. Cannot parse ClientHello: Invalid ClientHello packet: payload_decrypt_error ({data.hex()})", + WARNING, + ) + << tls.TlsFailedClientHook(tutils.Placeholder()) + ) + assert client_layer.tunnel_state == tls.tunnel.TunnelState.ESTABLISHING + + def test_invalid_fragmented_clienthello(self, tctx: context.Context): + client_layer = ClientQuicLayer(tctx, time=time.time) + playbook = tutils.Playbook(client_layer) + + assert not tctx.client.sni + + invalid_frag2 = ( + fragmented_client_hello2[:300] + b"\x00" + fragmented_client_hello2[300:] + ) + data = fragmented_client_hello1 + b"\n" + invalid_frag2 + + assert ( + playbook + >> events.Start() + >> events.DataReceived(tctx.client, fragmented_client_hello1) + >> events.DataReceived(tctx.client, invalid_frag2) + << commands.Log( + f"Client QUIC handshake failed. Cannot parse ClientHello: Invalid ClientHello packet: payload_decrypt_error ({data.hex()})", WARNING, ) << tls.TlsFailedClientHook(tutils.Placeholder()) @@ -1248,5 +1107,5 @@ def test_tls_reset(self, tctx: context.Context): tctx.client.tls = True tctx.client.sni = "some" DummyLayer(tctx) - quic.ClientQuicLayer(tctx, time=lambda: 0) + ClientQuicLayer(tctx, time=lambda: 0) assert tctx.client.sni is None diff --git a/test/mitmproxy/proxy/layers/test_dns.py b/test/mitmproxy/proxy/layers/test_dns.py index 133ae20b3c..3ce36273b3 100644 --- a/test/mitmproxy/proxy/layers/test_dns.py +++ b/test/mitmproxy/proxy/layers/test_dns.py @@ -1,9 +1,17 @@ +import struct import time +import pytest +from hypothesis import given +from hypothesis import HealthCheck +from hypothesis import settings +from hypothesis import strategies as st + from ..tutils import Placeholder from ..tutils import Playbook from ..tutils import reply from mitmproxy.dns import DNSFlow +from mitmproxy.net.dns import response_codes from mitmproxy.proxy.commands import CloseConnection from mitmproxy.proxy.commands import Log from mitmproxy.proxy.commands import OpenConnection @@ -11,14 +19,46 @@ from mitmproxy.proxy.events import ConnectionClosed from mitmproxy.proxy.events import DataReceived from mitmproxy.proxy.layers import dns -from mitmproxy.test.tutils import tdnsreq -from mitmproxy.test.tutils import tdnsresp +from mitmproxy.test.tflow import tdnsreq +from mitmproxy.test.tflow import tdnsresp +from mitmproxy.test.tflow import terr + + +@settings(suppress_health_check=[HealthCheck.function_scoped_fixture]) +@given(st.binary()) +def test_fuzz_unpack_tcp_message(tctx, data): + layer = dns.DNSLayer(tctx) + try: + layer.unpack_message(data, True) + except struct.error: + pass + + +@settings(suppress_health_check=[HealthCheck.function_scoped_fixture]) +@given(st.binary()) +def test_fuzz_unpack_udp_message(tctx, data): + tctx.client.transport_protocol = "udp" + tctx.server.transport_protocol = "udp" + + layer = dns.DNSLayer(tctx) + try: + layer.unpack_message(data, True) + except struct.error: + pass -def test_invalid_and_dummy_end(tctx): +@pytest.mark.parametrize("transport_protocol", ["tcp", "udp"]) +def test_invalid_and_dummy_end(tctx, transport_protocol): + tctx.client.transport_protocol = transport_protocol + tctx.server.transport_protocol = transport_protocol + + data = b"Not a DNS packet" + if tctx.client.transport_protocol == "tcp": + data = struct.pack("!H", len(data)) + data + assert ( Playbook(dns.DNSLayer(tctx)) - >> DataReceived(tctx.client, b"Not a DNS packet") + >> DataReceived(tctx.client, data) << Log( "Client(client:1234, state=open) sent an invalid message: question #0: unpack encountered a label of length 99" ) @@ -27,7 +67,11 @@ def test_invalid_and_dummy_end(tctx): ) -def test_regular(tctx): +@pytest.mark.parametrize("transport_protocol", ["tcp", "udp"]) +def test_regular(tctx, transport_protocol): + tctx.client.transport_protocol = transport_protocol + tctx.server.transport_protocol = transport_protocol + f = Placeholder(DNSFlow) req = tdnsreq() @@ -43,12 +87,12 @@ def resolve(flow: DNSFlow): assert ( Playbook(dns.DNSLayer(tctx)) - >> DataReceived(tctx.client, req.packed) + >> DataReceived(tctx.client, dns.pack_message(req, transport_protocol)) << dns.DnsRequestHook(f) >> reply(side_effect=resolve) << dns.DnsResponseHook(f) >> reply() - << SendData(tctx.client, resp.packed) + << SendData(tctx.client, dns.pack_message(resp, transport_protocol)) >> ConnectionClosed(tctx.client) << None ) @@ -57,7 +101,11 @@ def resolve(flow: DNSFlow): assert not f().live -def test_regular_mode_no_hook(tctx): +@pytest.mark.parametrize("transport_protocol", ["tcp", "udp"]) +def test_regular_mode_no_hook(tctx, transport_protocol): + tctx.client.transport_protocol = transport_protocol + tctx.server.transport_protocol = transport_protocol + f = Placeholder(DNSFlow) layer = dns.DNSLayer(tctx) layer.context.server.address = None @@ -72,20 +120,35 @@ def no_resolve(flow: DNSFlow): assert ( Playbook(layer) - >> DataReceived(tctx.client, req.packed) + >> DataReceived( + tctx.client, dns.pack_message(req, tctx.client.transport_protocol) + ) << dns.DnsRequestHook(f) >> reply(side_effect=no_resolve) << dns.DnsErrorHook(f) >> reply() + << SendData( + tctx.client, + dns.pack_message( + req.fail(response_codes.SERVFAIL), tctx.client.transport_protocol + ), + ) >> ConnectionClosed(tctx.client) << None ) assert f().request == req assert not f().response assert not f().live + assert ( + f().error.msg == "No hook has set a response and there is no upstream server." + ) -def test_reverse_premature_close(tctx): +@pytest.mark.parametrize("transport_protocol", ["tcp", "udp"]) +def test_reverse_premature_close(tctx, transport_protocol): + tctx.client.transport_protocol = transport_protocol + tctx.server.transport_protocol = transport_protocol + f = Placeholder(DNSFlow) layer = dns.DNSLayer(tctx) layer.context.server.address = ("8.8.8.8", 53) @@ -94,12 +157,14 @@ def test_reverse_premature_close(tctx): assert ( Playbook(layer) - >> DataReceived(tctx.client, req.packed) + >> DataReceived( + tctx.client, dns.pack_message(req, tctx.client.transport_protocol) + ) << dns.DnsRequestHook(f) >> reply() << OpenConnection(tctx.server) >> reply(None) - << SendData(tctx.server, req.packed) + << SendData(tctx.server, dns.pack_message(req, tctx.server.transport_protocol)) >> ConnectionClosed(tctx.client) << CloseConnection(tctx.server) << None @@ -111,7 +176,41 @@ def test_reverse_premature_close(tctx): assert f().request == req -def test_reverse(tctx): +def test_regular_hook_err(tctx): + f = Placeholder(DNSFlow) + + req = tdnsreq() + + def err(flow: DNSFlow): + flow.error = terr() + + assert ( + Playbook(dns.DNSLayer(tctx)) + >> DataReceived( + tctx.client, dns.pack_message(req, tctx.client.transport_protocol) + ) + << dns.DnsRequestHook(f) + >> reply(side_effect=err) + << dns.DnsErrorHook(f) + >> reply() + << SendData( + tctx.client, + dns.pack_message( + req.fail(response_codes.SERVFAIL), tctx.client.transport_protocol + ), + ) + >> ConnectionClosed(tctx.client) + << None + ) + assert f().error + assert not f().live + + +@pytest.mark.parametrize("transport_protocol", ["tcp", "udp"]) +def test_reverse(tctx, transport_protocol): + tctx.client.transport_protocol = transport_protocol + tctx.server.transport_protocol = transport_protocol + f = Placeholder(DNSFlow) layer = dns.DNSLayer(tctx) layer.context.server.address = ("8.8.8.8", 53) @@ -121,16 +220,20 @@ def test_reverse(tctx): assert ( Playbook(layer) - >> DataReceived(tctx.client, req.packed) + >> DataReceived( + tctx.client, dns.pack_message(req, tctx.client.transport_protocol) + ) << dns.DnsRequestHook(f) >> reply() << OpenConnection(tctx.server) >> reply(None) - << SendData(tctx.server, req.packed) - >> DataReceived(tctx.server, resp.packed) + << SendData(tctx.server, dns.pack_message(req, tctx.server.transport_protocol)) + >> DataReceived( + tctx.server, dns.pack_message(resp, tctx.server.transport_protocol) + ) << dns.DnsResponseHook(f) >> reply() - << SendData(tctx.client, resp.packed) + << SendData(tctx.client, dns.pack_message(resp, tctx.client.transport_protocol)) >> ConnectionClosed(tctx.client) << CloseConnection(tctx.server) << None @@ -143,7 +246,11 @@ def test_reverse(tctx): assert f().request == req and f().response == resp -def test_reverse_fail_connection(tctx): +@pytest.mark.parametrize("transport_protocol", ["tcp", "udp"]) +def test_reverse_fail_connection(tctx, transport_protocol): + tctx.client.transport_protocol = transport_protocol + tctx.server.transport_protocol = transport_protocol + f = Placeholder(DNSFlow) layer = dns.DNSLayer(tctx) layer.context.server.address = ("8.8.8.8", 53) @@ -152,13 +259,21 @@ def test_reverse_fail_connection(tctx): assert ( Playbook(layer) - >> DataReceived(tctx.client, req.packed) + >> DataReceived( + tctx.client, dns.pack_message(req, tctx.client.transport_protocol) + ) << dns.DnsRequestHook(f) >> reply() << OpenConnection(tctx.server) >> reply("UDP no likey today.") << dns.DnsErrorHook(f) >> reply() + << SendData( + tctx.client, + dns.pack_message( + req.fail(response_codes.SERVFAIL), tctx.client.transport_protocol + ), + ) << None ) assert f().request @@ -168,7 +283,11 @@ def test_reverse_fail_connection(tctx): assert f().request == req -def test_reverse_with_query_resend(tctx): +@pytest.mark.parametrize("transport_protocol", ["tcp", "udp"]) +def test_reverse_with_query_resend(tctx, transport_protocol): + tctx.client.transport_protocol = transport_protocol + tctx.server.transport_protocol = transport_protocol + f = Placeholder(DNSFlow) layer = dns.DNSLayer(tctx) layer.context.server.address = ("8.8.8.8", 53) @@ -180,20 +299,26 @@ def test_reverse_with_query_resend(tctx): assert ( Playbook(layer) - >> DataReceived(tctx.client, req.packed) + >> DataReceived( + tctx.client, dns.pack_message(req, tctx.client.transport_protocol) + ) << dns.DnsRequestHook(f) >> reply() << OpenConnection(tctx.server) >> reply(None) - << SendData(tctx.server, req.packed) - >> DataReceived(tctx.client, req2.packed) + << SendData(tctx.server, dns.pack_message(req, tctx.server.transport_protocol)) + >> DataReceived( + tctx.client, dns.pack_message(req2, tctx.client.transport_protocol) + ) << dns.DnsRequestHook(f) >> reply() - << SendData(tctx.server, req2.packed) - >> DataReceived(tctx.server, resp.packed) + << SendData(tctx.server, dns.pack_message(req2, tctx.server.transport_protocol)) + >> DataReceived( + tctx.server, dns.pack_message(resp, tctx.server.transport_protocol) + ) << dns.DnsResponseHook(f) >> reply() - << SendData(tctx.client, resp.packed) + << SendData(tctx.client, dns.pack_message(resp, tctx.client.transport_protocol)) >> ConnectionClosed(tctx.client) << CloseConnection(tctx.server) << None @@ -205,3 +330,151 @@ def test_reverse_with_query_resend(tctx): resp.timestamp = f().response.timestamp assert f().request == req2 assert f().response == resp + + +def test_tcp_message_over_multiple_events(tctx): + tctx.client.transport_protocol = "tcp" + tctx.server.transport_protocol = "tcp" + + layer = dns.DNSLayer(tctx) + layer.context.server.address = ("8.8.8.8", 53) + f = Placeholder(DNSFlow) + req = tdnsreq() + resp = tdnsresp() + resp_bytes = dns.pack_message(resp, tctx.client.transport_protocol) + split = len(resp_bytes) // 2 + + assert ( + Playbook(layer) + >> DataReceived( + tctx.client, dns.pack_message(req, tctx.client.transport_protocol) + ) + << dns.DnsRequestHook(f) + >> reply() + << OpenConnection(tctx.server) + >> reply(None) + << SendData(tctx.server, dns.pack_message(req, tctx.server.transport_protocol)) + >> DataReceived(tctx.server, resp_bytes[:split]) + >> DataReceived(tctx.server, resp_bytes[split:]) + << dns.DnsResponseHook(f) + >> reply() + << SendData(tctx.client, dns.pack_message(resp, tctx.client.transport_protocol)) + >> ConnectionClosed(tctx.client) + << CloseConnection(tctx.server) + << None + ) + + +def test_query_pipelining_same_event(tctx): + tctx.client.transport_protocol = "tcp" + tctx.server.transport_protocol = "tcp" + + layer = dns.DNSLayer(tctx) + layer.context.server.address = ("8.8.8.8", 53) + f1 = Placeholder(DNSFlow) + f2 = Placeholder(DNSFlow) + req1 = tdnsreq(id=1) + req2 = tdnsreq(id=2) + resp1 = tdnsresp(id=1) + resp2 = tdnsresp(id=2) + req_bytes = dns.pack_message( + req1, tctx.client.transport_protocol + ) + dns.pack_message(req2, tctx.client.transport_protocol) + + assert ( + Playbook(layer) + >> DataReceived(tctx.client, req_bytes) + << dns.DnsRequestHook(f1) + >> reply() + << OpenConnection(tctx.server) + >> reply(None) + << SendData(tctx.server, dns.pack_message(req1, tctx.server.transport_protocol)) + << dns.DnsRequestHook(f2) + >> reply() + << SendData(tctx.server, dns.pack_message(req2, tctx.server.transport_protocol)) + >> DataReceived( + tctx.server, dns.pack_message(resp1, tctx.server.transport_protocol) + ) + << dns.DnsResponseHook(f1) + >> reply() + << SendData( + tctx.client, dns.pack_message(resp1, tctx.server.transport_protocol) + ) + >> DataReceived( + tctx.server, dns.pack_message(resp2, tctx.server.transport_protocol) + ) + << dns.DnsResponseHook(f2) + >> reply() + << SendData( + tctx.client, dns.pack_message(resp2, tctx.server.transport_protocol) + ) + >> ConnectionClosed(tctx.client) + << CloseConnection(tctx.server) + << None + ) + + +def test_query_pipelining_multiple_events(tctx): + tctx.client.transport_protocol = "tcp" + tctx.server.transport_protocol = "tcp" + + layer = dns.DNSLayer(tctx) + layer.context.server.address = ("8.8.8.8", 53) + f1 = Placeholder(DNSFlow) + f2 = Placeholder(DNSFlow) + req1 = tdnsreq(id=1) + req2 = tdnsreq(id=2) + resp1 = tdnsresp(id=1) + resp2 = tdnsresp(id=2) + req_bytes = dns.pack_message( + req1, tctx.client.transport_protocol + ) + dns.pack_message(req2, tctx.client.transport_protocol) + split = len(req_bytes) * 3 // 4 + + assert ( + Playbook(layer) + >> DataReceived(tctx.client, req_bytes[:split]) + << dns.DnsRequestHook(f1) + >> reply() + << OpenConnection(tctx.server) + >> reply(None) + << SendData(tctx.server, dns.pack_message(req1, tctx.server.transport_protocol)) + >> DataReceived( + tctx.server, dns.pack_message(resp1, tctx.server.transport_protocol) + ) + << dns.DnsResponseHook(f1) + >> reply() + << SendData( + tctx.client, dns.pack_message(resp1, tctx.server.transport_protocol) + ) + >> DataReceived(tctx.client, req_bytes[split:]) + << dns.DnsRequestHook(f2) + >> reply() + << SendData(tctx.server, dns.pack_message(req2, tctx.server.transport_protocol)) + >> DataReceived( + tctx.server, dns.pack_message(resp2, tctx.server.transport_protocol) + ) + << dns.DnsResponseHook(f2) + >> reply() + << SendData( + tctx.client, dns.pack_message(resp2, tctx.server.transport_protocol) + ) + >> ConnectionClosed(tctx.client) + << CloseConnection(tctx.server) + << None + ) + + +def test_invalid_tcp_message_length(tctx): + tctx.client.transport_protocol = "tcp" + tctx.server.transport_protocol = "tcp" + + assert ( + Playbook(dns.DNSLayer(tctx)) + >> DataReceived(tctx.client, b"\x00\x00") + << Log( + "Client(client:1234, state=open) sent an invalid message: Message length field cannot be zero" + ) + << CloseConnection(tctx.client) + >> ConnectionClosed(tctx.client) + ) diff --git a/test/mitmproxy/proxy/layers/test_modes.py b/test/mitmproxy/proxy/layers/test_modes.py index f99685c3f5..8ad48c74d2 100644 --- a/test/mitmproxy/proxy/layers/test_modes.py +++ b/test/mitmproxy/proxy/layers/test_modes.py @@ -174,6 +174,9 @@ def test_reverse_proxy(tctx, keep_host_header): def test_reverse_dns(tctx): + tctx.client.transport_protocol = "udp" + tctx.server.transport_protocol = "udp" + f = Placeholder(dns.DNSFlow) server = Placeholder(Server) tctx.client.proxy_mode = ProxyMode.parse("reverse:dns://8.8.8.8:53") @@ -196,8 +199,8 @@ def test_reverse_dns(tctx): def test_quic(tctx: Context, keep_host_header: bool): with taddons.context(): tctx.options.keep_host_header = keep_host_header - tctx.server.sni = "other" - tctx.client.proxy_mode = ProxyMode.parse("reverse:quic://1.2.3.4:5") + tctx.server.sni = "other.example.com" + tctx.client.proxy_mode = ProxyMode.parse("reverse:quic://example.org:443") client_hello = Placeholder(bytes) def set_settings(data: quic.QuicTlsData): @@ -215,9 +218,9 @@ def set_settings(data: quic.QuicTlsData): << SendData(tctx.server, client_hello) << RequestWakeup(Placeholder(float)) ) - assert tctx.server.address == ("1.2.3.4", 5) - assert quic.quic_parse_client_hello(client_hello()).sni == ( - "other" if keep_host_header else "1.2.3.4" + assert tctx.server.address == ("example.org", 443) + assert quic.quic_parse_client_hello_from_datagrams([client_hello()]).sni == ( + "other.example.com" if keep_host_header else "example.org" ) @@ -448,7 +451,7 @@ def test_socks5_trickle(tctx: Context): r"Unsupported SOCKS5 request: b'\x05\x02\x00\x01\x7f\x00\x00\x01\x124'", ), ( - CLIENT_HELLO + b"\x05\x01\x00\xFF\x00\x00", + CLIENT_HELLO + b"\x05\x01\x00\xff\x00\x00", SERVER_HELLO + b"\x05\x08\x00\x01\x00\x00\x00\x00\x00\x00", r"Unknown address type: 255", ), @@ -527,7 +530,7 @@ def test_socks5_auth_success( b"\x05\x01\x00", None, None, - b"\x05\xFF\x00\x01\x00\x00\x00\x00\x00\x00", + b"\x05\xff\x00\x01\x00\x00\x00\x00\x00\x00", "Client does not support SOCKS5 with user/password authentication.", ), ( diff --git a/test/mitmproxy/proxy/layers/test_tls.py b/test/mitmproxy/proxy/layers/test_tls.py index 9960f8b748..6e08fa7c10 100644 --- a/test/mitmproxy/proxy/layers/test_tls.py +++ b/test/mitmproxy/proxy/layers/test_tls.py @@ -665,8 +665,10 @@ def test_mitmproxy_ca_is_untrusted(self, tctx: context.Context): playbook >> events.DataReceived(tctx.client, tssl_client.bio_read()) << commands.Log( - "Client TLS handshake failed. The client does not trust the proxy's certificate " - "for wrong.host.mitmproxy.org (sslv3 alert bad certificate)", + tutils.StrMatching( + "Client TLS handshake failed. The client does not trust the proxy's certificate " + "for wrong.host.mitmproxy.org" + ), WARNING, ) << tls.TlsFailedClientHook(tls_hook_data) diff --git a/test/mitmproxy/proxy/layers/test_udp.py b/test/mitmproxy/proxy/layers/test_udp.py index 9b8d3b419f..1253a510a0 100644 --- a/test/mitmproxy/proxy/layers/test_udp.py +++ b/test/mitmproxy/proxy/layers/test_udp.py @@ -59,7 +59,6 @@ def test_simple(tctx): << SendData(tctx.client, b"hi") >> ConnectionClosed(tctx.server) << CloseConnection(tctx.client) - >> ConnectionClosed(tctx.client) << udp.UdpEndHook(f) >> reply() >> DataReceived(tctx.server, b"ignored") diff --git a/test/mitmproxy/proxy/layers/test_websocket.py b/test/mitmproxy/proxy/layers/test_websocket.py index eebca259dd..0749b690a1 100644 --- a/test/mitmproxy/proxy/layers/test_websocket.py +++ b/test/mitmproxy/proxy/layers/test_websocket.py @@ -130,7 +130,9 @@ def test_upgrade(tctx): def test_upgrade_streamed(tctx): - """If the HTTP response is streamed, we may get early data from the client.""" + """ + Test that streaming the response does not change behavior. + """ tctx.server.address = ("example.com", 80) tctx.server.state = ConnectionState.OPEN flow = Placeholder(HTTPFlow) @@ -169,6 +171,10 @@ def enable_streaming(flow: HTTPFlow): ) << http.HttpResponseHeadersHook(flow) >> reply(side_effect=enable_streaming) + # Current implementation: We know that body size for 101 responses must be zero, + # so we never trigger streaming logic in the first place. + << http.HttpResponseHook(flow) + >> reply() << SendData( tctx.client, b"HTTP/1.1 101 Switching Protocols\r\n" @@ -176,11 +182,9 @@ def enable_streaming(flow: HTTPFlow): b"Connection: Upgrade\r\n" b"\r\n", ) - << http.HttpResponseHook(flow) - >> DataReceived(tctx.client, masked_bytes(b"\x81\x0bhello world")) # early !! - >> reply(to=-2) << websocket.WebsocketStartHook(flow) - >> reply() + >> DataReceived(tctx.client, masked_bytes(b"\x81\x0bhello world")) # early data + >> reply(to=-2) << websocket.WebsocketMessageHook(flow) >> reply() << SendData(tctx.server, masked(b"\x81\x0bhello world")) @@ -410,9 +414,9 @@ def test_close_code(ws_testdata): def test_deflate(ws_testdata): tctx, playbook, flow = ws_testdata - flow.response.headers[ - "Sec-WebSocket-Extensions" - ] = "permessage-deflate; server_max_window_bits=10" + flow.response.headers["Sec-WebSocket-Extensions"] = ( + "permessage-deflate; server_max_window_bits=10" + ) assert ( playbook << websocket.WebsocketStartHook(flow) diff --git a/test/mitmproxy/proxy/test_layer.py b/test/mitmproxy/proxy/test_layer.py index b646c2e027..307dd546dc 100644 --- a/test/mitmproxy/proxy/test_layer.py +++ b/test/mitmproxy/proxy/test_layer.py @@ -73,8 +73,8 @@ def state_bar(self, event: events.Event) -> layer.CommandGenerator[None]: def test_debug_shorten(self, tctx): t = layer.Layer(tctx) t.debug = " " - assert t._Layer__debug("x" * 600).message == " " + "x" * 512 + "…" - assert t._Layer__debug("x" * 600).message == " " + "x" * 256 + "…" + assert t._Layer__debug("x" * 4096).message == " " + "x" * 2048 + "…" + assert t._Layer__debug("x" * 4096).message == " " + "x" * 256 + "…" assert t._Layer__debug("foo").message == " foo" diff --git a/test/mitmproxy/proxy/test_mode_servers.py b/test/mitmproxy/proxy/test_mode_servers.py index 274eabe425..23e40d8bc7 100644 --- a/test/mitmproxy/proxy/test_mode_servers.py +++ b/test/mitmproxy/proxy/test_mode_servers.py @@ -1,17 +1,15 @@ import asyncio import platform -from typing import cast from unittest.mock import AsyncMock from unittest.mock import MagicMock from unittest.mock import Mock -import mitmproxy_rs import pytest +from ...conftest import no_ipv6 import mitmproxy.platform +import mitmproxy_rs from mitmproxy.addons.proxyserver import Proxyserver -from mitmproxy.net import udp -from mitmproxy.proxy.mode_servers import DnsInstance from mitmproxy.proxy.mode_servers import LocalRedirectorInstance from mitmproxy.proxy.mode_servers import ServerInstance from mitmproxy.proxy.mode_servers import WireGuardServerInstance @@ -263,12 +261,13 @@ async def test_udp_start_stop(caplog_async): assert await caplog_async.await_log("server listening") host, port, *_ = inst.listen_addrs[0] - reader, writer = await udp.open_connection(host, port) + stream = await mitmproxy_rs.udp.open_udp_connection(host, port) - writer.write(b"\x00\x00\x01") + stream.write(b"\x00\x00\x01") assert await caplog_async.await_log("sent an invalid message") - writer.close() + stream.close() + await stream.wait_closed() await inst.stop() assert await caplog_async.await_log("stopped") @@ -278,59 +277,77 @@ async def test_udp_start_error(): manager = MagicMock() with taddons.context(): - inst = ServerInstance.make("dns@127.0.0.1:0", manager) + inst = ServerInstance.make("reverse:udp://127.0.0.1:1234@127.0.0.1:0", manager) await inst.start() port = inst.listen_addrs[0][1] - inst2 = ServerInstance.make(f"dns@127.0.0.1:{port}", manager) + inst2 = ServerInstance.make( + f"reverse:udp://127.0.0.1:1234@127.0.0.1:{port}", manager + ) with pytest.raises( - OSError, match=f"server failed to listen on 127\\.0\\.0\\.1:{port}" + Exception, match=f"Failed to bind UDP socket to 127.0.0.1:{port}" ): await inst2.start() await inst.stop() -async def test_udp_connection_reuse(monkeypatch): +@pytest.mark.parametrize("ip_version", ["v4", "v6"]) +@pytest.mark.parametrize("protocol", ["tcp", "udp"]) +async def test_dual_stack(ip_version, protocol, caplog_async): + """Test that a server bound to "" binds on both IPv4 and IPv6 for both TCP and UDP.""" + + if ip_version == "v6" and no_ipv6: + pytest.skip("Skipped because IPv6 is unavailable.") + + if ip_version == "v4": + addr = "127.0.0.1" + else: + addr = "::1" + + caplog_async.set_level("DEBUG") manager = MagicMock() manager.connections = {} - monkeypatch.setattr(udp, "DatagramWriter", MagicMock()) - monkeypatch.setattr(DnsInstance, "handle_udp_connection", AsyncMock()) - with taddons.context(): - inst = cast(DnsInstance, ServerInstance.make("dns", manager)) - inst.handle_udp_datagram( - MagicMock(), b"\x00\x00\x01", ("remoteaddr", 0), ("localaddr", 0) - ) - inst.handle_udp_datagram( - MagicMock(), b"\x00\x00\x02", ("remoteaddr", 0), ("localaddr", 0) - ) - await asyncio.sleep(0) + inst = ServerInstance.make("dns@0", manager) + await inst.start() + assert await caplog_async.await_log("server listening") + _, port, *_ = inst.listen_addrs[0] - assert len(inst.manager.connections) == 1 + if protocol == "tcp": + _, stream = await asyncio.open_connection(addr, port) + else: + stream = await mitmproxy_rs.udp.open_udp_connection(addr, port) + stream.write(b"\x00\x00\x01") + assert await caplog_async.await_log("sent an invalid message") + stream.close() + await stream.wait_closed() + await inst.stop() + assert await caplog_async.await_log("stopped") -async def test_udp_dual_stack(caplog_async): - caplog_async.set_level("DEBUG") + +@pytest.mark.parametrize("transport_protocol", ["udp", "tcp"]) +async def test_dns_start_stop(caplog_async, transport_protocol): + caplog_async.set_level("INFO") manager = MagicMock() manager.connections = {} with taddons.context(): - inst = ServerInstance.make("dns@:0", manager) + inst = ServerInstance.make("dns@127.0.0.1:0", manager) await inst.start() assert await caplog_async.await_log("server listening") - _, port, *_ = inst.listen_addrs[0] - reader, writer = await udp.open_connection("127.0.0.1", port) - writer.write(b"\x00\x00\x01") + host, port, *_ = inst.listen_addrs[0] + if transport_protocol == "tcp": + _, stream = await asyncio.open_connection("127.0.0.1", port) + elif transport_protocol == "udp": + stream = await mitmproxy_rs.udp.open_udp_connection("127.0.0.1", port) + + stream.write(b"\x00\x00\x01") assert await caplog_async.await_log("sent an invalid message") - writer.close() - if "listening on IPv4 only" not in caplog_async.caplog.text: - caplog_async.clear() - reader, writer = await udp.open_connection("::1", port) - writer.write(b"\x00\x00\x01") - assert await caplog_async.await_log("sent an invalid message") - writer.close() + stream.close() + await stream.wait_closed() await inst.stop() assert await caplog_async.await_log("stopped") @@ -338,8 +355,10 @@ async def test_udp_dual_stack(caplog_async): @pytest.fixture() def patched_local_redirector(monkeypatch): - start_local_redirector = AsyncMock() - monkeypatch.setattr(mitmproxy_rs, "start_local_redirector", start_local_redirector) + start_local_redirector = AsyncMock(return_value=Mock()) + monkeypatch.setattr( + mitmproxy_rs.local, "start_local_redirector", start_local_redirector + ) # make sure _server and _instance are restored after this test monkeypatch.setattr(LocalRedirectorInstance, "_server", None) monkeypatch.setattr(LocalRedirectorInstance, "_instance", None) @@ -396,19 +415,15 @@ async def test_always_uses_current_instance(patched_local_redirector, monkeypatc manager = MagicMock() with taddons.context(): - inst1 = ServerInstance.make(f"local:curl", manager) + inst1 = LocalRedirectorInstance.make(f"local:curl", manager) await inst1.start() await inst1.stop() - handle_tcp, handle_udp = patched_local_redirector.await_args[0] + handle_stream, _ = patched_local_redirector.await_args[0] - inst2 = ServerInstance.make(f"local:wget", manager) + inst2 = LocalRedirectorInstance.make(f"local:wget", manager) await inst2.start() - monkeypatch.setattr(inst2, "handle_tcp_connection", h_tcp := AsyncMock()) - await handle_tcp(Mock()) - assert h_tcp.await_count - - monkeypatch.setattr(inst2, "handle_udp_datagram", h_udp := Mock()) - handle_udp(Mock(), b"", ("", 0), ("", 0)) - assert h_udp.called + monkeypatch.setattr(inst2, "handle_stream", handler := AsyncMock()) + await handle_stream(Mock()) + assert handler.await_count diff --git a/test/mitmproxy/proxy/test_mode_specs.py b/test/mitmproxy/proxy/test_mode_specs.py index d5e4ad29db..9c7889eb10 100644 --- a/test/mitmproxy/proxy/test_mode_specs.py +++ b/test/mitmproxy/proxy/test_mode_specs.py @@ -42,6 +42,7 @@ def test_listen_addr(): assert ProxyMode.parse("regular@1234").listen_port() == 1234 assert ProxyMode.parse("regular").listen_port(default=4424) == 4424 assert ProxyMode.parse("regular@1234").listen_port(default=4424) == 1234 + assert ProxyMode.parse("local").listen_port() is None assert ProxyMode.parse("regular").listen_host() == "" assert ProxyMode.parse("regular@127.0.0.2:8080").listen_host() == "127.0.0.2" diff --git a/test/mitmproxy/proxy/test_server.py b/test/mitmproxy/proxy/test_server.py index e69de29bb2..40448eecc0 100644 --- a/test/mitmproxy/proxy/test_server.py +++ b/test/mitmproxy/proxy/test_server.py @@ -0,0 +1,106 @@ +import asyncio +import collections +import textwrap +from dataclasses import dataclass +from typing import Callable +from unittest import mock + +import pytest + +from mitmproxy import options +from mitmproxy.connection import Server +from mitmproxy.proxy import commands +from mitmproxy.proxy import layer +from mitmproxy.proxy import server +from mitmproxy.proxy import server_hooks +from mitmproxy.proxy.events import Event +from mitmproxy.proxy.events import HookCompleted +from mitmproxy.proxy.events import Start +from mitmproxy.proxy.mode_specs import ProxyMode + + +class MockConnectionHandler(server.SimpleConnectionHandler): + hook_handlers: dict[str, mock.Mock | Callable] + + def __init__(self): + super().__init__( + reader=mock.Mock(), + writer=mock.Mock(), + options=options.Options(), + mode=ProxyMode.parse("regular"), + hook_handlers=collections.defaultdict(lambda: mock.Mock()), + ) + + +@pytest.mark.parametrize("result", ("success", "killed", "failed")) +async def test_open_connection(result, monkeypatch): + handler = MockConnectionHandler() + server_connect = handler.hook_handlers["server_connect"] + server_connected = handler.hook_handlers["server_connected"] + server_connect_error = handler.hook_handlers["server_connect_error"] + server_disconnected = handler.hook_handlers["server_disconnected"] + + match result: + case "success": + monkeypatch.setattr( + asyncio, + "open_connection", + mock.AsyncMock(return_value=(mock.MagicMock(), mock.MagicMock())), + ) + monkeypatch.setattr( + MockConnectionHandler, "handle_connection", mock.AsyncMock() + ) + case "failed": + monkeypatch.setattr( + asyncio, "open_connection", mock.AsyncMock(side_effect=OSError) + ) + case "killed": + + def _kill(d: server_hooks.ServerConnectionHookData) -> None: + d.server.error = "do not connect" + + server_connect.side_effect = _kill + + await handler.open_connection( + commands.OpenConnection(connection=Server(address=("server", 1234))) + ) + + assert server_connect.call_args[0][0].server.address == ("server", 1234) + + assert server_connected.called == (result == "success") + assert server_connect_error.called == (result != "success") + + assert server_disconnected.called == (result == "success") + + +async def test_no_reentrancy(capsys): + class ReentrancyTestLayer(layer.Layer): + def handle_event(self, event: Event) -> layer.CommandGenerator[None]: + if isinstance(event, Start): + print("Starting...") + yield FastHook() + print("Start completed.") + elif isinstance(event, HookCompleted): + print(f"Hook completed (must not happen before start is completed).") + + def _handle_event(self, event: Event) -> layer.CommandGenerator[None]: + raise NotImplementedError + + @dataclass + class FastHook(commands.StartHook): + pass + + handler = MockConnectionHandler() + handler.layer = ReentrancyTestLayer(handler.layer.context) + + # This instead would fail: handler._server_event(Start()) + await handler.server_event(Start()) + await asyncio.sleep(0) + + assert capsys.readouterr().out == textwrap.dedent( + """\ + Starting... + Start completed. + Hook completed (must not happen before start is completed). + """ + ) diff --git a/test/mitmproxy/proxy/test_tutils.py b/test/mitmproxy/proxy/test_tutils.py index ec676405b3..735b31dda5 100644 --- a/test/mitmproxy/proxy/test_tutils.py +++ b/test/mitmproxy/proxy/test_tutils.py @@ -114,6 +114,12 @@ def test_command_reply(tplaybook): assert tplaybook assert tplaybook.actual[1] == tplaybook.actual[2].command + tplaybook >> TEvent((42,)) + tplaybook << TCommand(42) + tplaybook >> tutils.reply(to=TCommand) + assert tplaybook + assert tplaybook.actual[4] == tplaybook.actual[5].command + def test_default_playbook(tctx): p = tutils.Playbook(TLayer(tctx)) diff --git a/test/mitmproxy/proxy/test_utils.py b/test/mitmproxy/proxy/test_utils.py index b3504271d5..f4cc274cf4 100644 --- a/test/mitmproxy/proxy/test_utils.py +++ b/test/mitmproxy/proxy/test_utils.py @@ -1,6 +1,7 @@ import pytest from mitmproxy.proxy.utils import expect +from mitmproxy.proxy.utils import ReceiveBuffer def test_expect(): @@ -19,3 +20,25 @@ def bar(self, x): assert list(f.bar("bar")) == ["rab"] with pytest.raises(AssertionError, match=r"Expected str\|int, got None."): f.foo(None) + + +def test_receive_buffer(): + buf = ReceiveBuffer() + assert len(buf) == 0 + assert bytes(buf) == b"" + assert not buf + + buf += b"foo" + assert len(buf) == 3 + assert bytes(buf) == b"foo" + assert buf + + buf += b"bar" + assert len(buf) == 6 + assert bytes(buf) == b"foobar" + assert buf + + buf.clear() + assert len(buf) == 0 + assert bytes(buf) == b"" + assert not buf diff --git a/test/mitmproxy/proxy/tutils.py b/test/mitmproxy/proxy/tutils.py index 22543e397d..5f3c74b93b 100644 --- a/test/mitmproxy/proxy/tutils.py +++ b/test/mitmproxy/proxy/tutils.py @@ -27,7 +27,7 @@ def _eq(a: PlaybookEntry, b: PlaybookEntry) -> bool: """Compare two commands/events, and possibly update placeholders.""" - if type(a) != type(b): + if type(a) is not type(b): return False a_dict = a.__dict__ @@ -159,6 +159,10 @@ def __init__( def __rshift__(self, e): """Add an event to send""" + if isinstance(e, collections.abc.Iterable): + for ev in e: + self.__rshift__(ev) + return self assert isinstance(e, events.Event) self.expected.append(e) return self @@ -167,6 +171,10 @@ def __lshift__(self, c): """Add an expected command""" if c is None: return self + if isinstance(c, collections.abc.Iterable): + for cmd in c: + self.__lshift__(cmd) + return self assert isinstance(c, commands.Command) prev = self.expected[-1] @@ -298,13 +306,13 @@ def __del__(self): class reply(events.Event): args: tuple[Any, ...] - to: commands.Command | int + to: commands.Command | type[commands.Command] | int side_effect: Callable[[Any], Any] def __init__( self, *args, - to: commands.Command | int = -1, + to: commands.Command | type[commands.Command] | int = -1, side_effect: Callable[[Any], None] = lambda x: None, ): """Utility method to reply to the latest hook in playbooks.""" @@ -322,6 +330,14 @@ def playbook_eval(self, playbook: Playbook) -> events.CommandCompleted: raise AssertionError(f"There is no command at offset {self.to}: {to}") else: self.to = to + elif isinstance(self.to, type): + for cmd in reversed(playbook.actual): + if isinstance(cmd, self.to): + assert isinstance(cmd, commands.Command) + self.to = cmd + break + else: + raise AssertionError(f"There is no command of type {self.to}.") for cmd in reversed(playbook.actual): if eq(self.to, cmd): self.to = cmd diff --git a/test/mitmproxy/test_certs.py b/test/mitmproxy/test_certs.py index d3c33727cb..9e80bfc99e 100644 --- a/test/mitmproxy/test_certs.py +++ b/test/mitmproxy/test_certs.py @@ -1,3 +1,4 @@ +import ipaddress import os from datetime import datetime from datetime import timezone @@ -73,16 +74,16 @@ def test_chain_file(self, tdata, tmp_path): assert len(ca.default_chain_certs) == 2 def test_sans(self, tstore): - c1 = tstore.get_cert("foo.com", ["*.bar.com"]) + c1 = tstore.get_cert("foo.com", [x509.DNSName("*.bar.com")]) tstore.get_cert("foo.bar.com", []) # assert c1 == c2 c3 = tstore.get_cert("bar.com", []) assert not c1 == c3 def test_sans_change(self, tstore): - tstore.get_cert("foo.com", ["*.bar.com"]) - entry = tstore.get_cert("foo.bar.com", ["*.baz.com"]) - assert "*.baz.com" in entry.cert.altnames + tstore.get_cert("foo.com", [x509.DNSName("*.bar.com")]) + entry = tstore.get_cert("foo.bar.com", [x509.DNSName("*.baz.com")]) + assert x509.DNSName("*.baz.com") in entry.cert.altnames def test_expire(self, tstore): tstore.STORE_CAP = 3 @@ -90,35 +91,22 @@ def test_expire(self, tstore): tstore.get_cert("two.com", []) tstore.get_cert("three.com", []) - assert ("one.com", ()) in tstore.certs - assert ("two.com", ()) in tstore.certs - assert ("three.com", ()) in tstore.certs + assert ("one.com", x509.GeneralNames([])) in tstore.certs + assert ("two.com", x509.GeneralNames([])) in tstore.certs + assert ("three.com", x509.GeneralNames([])) in tstore.certs tstore.get_cert("one.com", []) - assert ("one.com", ()) in tstore.certs - assert ("two.com", ()) in tstore.certs - assert ("three.com", ()) in tstore.certs + assert ("one.com", x509.GeneralNames([])) in tstore.certs + assert ("two.com", x509.GeneralNames([])) in tstore.certs + assert ("three.com", x509.GeneralNames([])) in tstore.certs tstore.get_cert("four.com", []) - assert ("one.com", ()) not in tstore.certs - assert ("two.com", ()) in tstore.certs - assert ("three.com", ()) in tstore.certs - assert ("four.com", ()) in tstore.certs - - def test_overrides(self, tmp_path): - ca1 = certs.CertStore.from_store(tmp_path / "ca1", "test", 2048) - ca2 = certs.CertStore.from_store(tmp_path / "ca2", "test", 2048) - assert not ca1.default_ca.serial == ca2.default_ca.serial - - dc = ca2.get_cert("foo.com", ["sans.example.com"]) - dcp = tmp_path / "dc" - dcp.write_bytes(dc.cert.to_pem()) - ca1.add_cert_file("foo.com", dcp) - - ret = ca1.get_cert("foo.com", []) - assert ret.cert.serial == dc.cert.serial + assert ("one.com", x509.GeneralNames([])) not in tstore.certs + assert ("two.com", x509.GeneralNames([])) in tstore.certs + assert ("three.com", x509.GeneralNames([])) in tstore.certs + assert ("four.com", x509.GeneralNames([])) in tstore.certs def test_create_dhparams(self, tmp_path): filename = tmp_path / "dhparam.pem" @@ -133,6 +121,23 @@ def test_umask_secret(self, tmpdir): # TODO: How do we actually attempt to read that file as another user? assert os.stat(filename).st_mode & 0o77 == 0 + @pytest.mark.parametrize( + "input,output", + [ + ( + "subdomain.example.com", + ["subdomain.example.com", "*.example.com", "*.com"], + ), + ( + x509.DNSName("subdomain.example.com"), + ["subdomain.example.com", "*.example.com", "*.com"], + ), + (x509.IPAddress(ipaddress.ip_address("127.0.0.1")), ["127.0.0.1"]), + ], + ) + def test_asterisk_forms(self, input, output): + assert certs.CertStore.asterisk_forms(input) == output + class TestDummyCert: def test_with_ca(self, tstore): @@ -140,17 +145,25 @@ def test_with_ca(self, tstore): tstore.default_privatekey, tstore.default_ca._cert, "foo.com", - ["one.com", "two.com", "*.three.com", "127.0.0.1", "bücher.example"], + [ + x509.DNSName("one.com"), + x509.DNSName("two.com"), + x509.DNSName("*.three.com"), + x509.IPAddress(ipaddress.ip_address("127.0.0.1")), + x509.DNSName("bücher.example".encode("idna").decode("ascii")), + ], "Foo Ltd.", ) assert r.cn == "foo.com" - assert r.altnames == [ - "one.com", - "two.com", - "*.three.com", - "xn--bcher-kva.example", - "127.0.0.1", - ] + assert r.altnames == x509.GeneralNames( + [ + x509.DNSName("one.com"), + x509.DNSName("two.com"), + x509.DNSName("*.three.com"), + x509.IPAddress(ipaddress.ip_address("127.0.0.1")), + x509.DNSName("xn--bcher-kva.example"), + ] + ) assert r.organization == "Foo Ltd." r = certs.dummy_cert( @@ -158,7 +171,7 @@ def test_with_ca(self, tstore): ) assert r.cn is None assert r.organization is None - assert r.altnames == [] + assert r.altnames == x509.GeneralNames([]) class TestCert: @@ -177,6 +190,7 @@ def test_simple(self, tdata): assert c2.cn == "www.inode.co.nz" assert len(c2.altnames) == 2 assert c2.fingerprint() + assert c2.public_key() assert c2.notbefore == datetime( year=2010, month=1, @@ -231,6 +245,19 @@ def test_keyinfo(self, tdata, filename, name, bits): c = certs.Cert.from_pem(d) assert c.keyinfo == (name, bits) + @pytest.mark.parametrize( + "filename,is_ca", + [ + ("mitmproxy/net/data/verificationcerts/trusted-leaf.crt", False), + ("mitmproxy/net/data/verificationcerts/trusted-root.crt", True), + ("mitmproxy/data/invalid-subject.pem", False), # no basic constraints + ], + ) + def test_is_ca(self, tdata, filename, is_ca): + pem = Path(tdata.path(filename)).read_bytes() + cert = certs.Cert.from_pem(pem) + assert cert.is_ca == is_ca + def test_err_broken_sans(self, tdata): with open(tdata.path("mitmproxy/net/data/text_cert_weird1"), "rb") as f: d = f.read() @@ -254,6 +281,14 @@ def test_state(self, tdata): c2.set_state(a) assert c == c2 + def test_add_cert_overrides(self, tdata, tstore): + certfile = Path( + tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.pem") + ) + cert = certs.Cert.from_pem(certfile.read_bytes()) + tstore.add_cert_file("example.com", certfile) + assert cert == tstore.get_cert("example.com", []).cert + def test_from_store_with_passphrase(self, tdata, tstore): tstore.add_cert_file( "unencrypted-no-pass", Path(tdata.path("mitmproxy/data/testkey.pem")), None @@ -276,6 +311,54 @@ def test_from_store_with_passphrase(self, tdata, tstore): None, ) + def test_add_cert_with_no_private_key(self, tdata, tstore): + with pytest.raises(ValueError, match="Unable to find private key"): + tstore.add_cert_file( + "example.com", + Path( + tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.crt") + ), + ) + + def test_add_cert_private_public_mismatch(self, tdata, tstore): + with pytest.raises( + ValueError, match='Private and public keys in ".+" do not match' + ): + tstore.add_cert_file( + "example.com", + Path( + tdata.path( + "mitmproxy/net/data/verificationcerts/private-public-mismatch.pem" + ) + ), + ) + + def test_add_cert_chain(self, tdata, tstore): + tstore.add_cert_file( + "example.com", + Path(tdata.path("mitmproxy/net/data/verificationcerts/trusted-chain.pem")), + ) + assert len(tstore.get_cert("example.com", []).chain_certs) == 2 + + def test_add_cert_chain_invalid(self, tdata, tstore, caplog): + tstore.add_cert_file( + "example.com", + Path( + tdata.path( + "mitmproxy/net/data/verificationcerts/trusted-chain-invalid.pem" + ) + ), + ) + assert "Failed to read certificate chain" in caplog.text + assert len(tstore.get_cert("example.com", []).chain_certs) == 1 + + def test_add_cert_is_ca(self, tdata, tstore, caplog): + tstore.add_cert_file( + "example.com", + Path(tdata.path("mitmproxy/net/data/verificationcerts/trusted-root.pem")), + ) + assert "is a certificate authority and not a leaf certificate" in caplog.text + def test_special_character(self, tdata): with open(tdata.path("mitmproxy/net/data/text_cert_with_comma"), "rb") as f: d = f.read() diff --git a/test/mitmproxy/test_dns.py b/test/mitmproxy/test_dns.py index 038f0ddb08..b6fa7c7b2b 100644 --- a/test/mitmproxy/test_dns.py +++ b/test/mitmproxy/test_dns.py @@ -28,6 +28,20 @@ def test_str(self): assert ( str(dns.ResourceRecord.TXT("test", "unicode text 😀")) == "unicode text 😀" ) + params = { + 0: b"\x00", + 1: b"\x01", + 2: b"", + 3: b"\x02", + 4: b"\x03", + 5: b"\x04", + 6: b"\x05", + } + record = dns.https_records.HTTPSRecord(1, "example.com", params) + assert ( + str(dns.ResourceRecord.HTTPS("example.com", record)) + == "priority: 1 target_name: 'example.com' {'mandatory': b'\\x00', 'alpn': b'\\x01', 'no_default_alpn': b'', 'port': b'\\x02', 'ipv4hint': b'\\x03', 'ech': b'\\x04', 'ipv6hint': b'\\x05'}" + ) assert ( str( dns.ResourceRecord( @@ -66,6 +80,37 @@ def test_setter(self): rr.text = "sample text" assert rr.text == "sample text" + def test_https_record_ech(self): + rr = dns.ResourceRecord( + "test", dns.types.ANY, dns.classes.IN, dns.ResourceRecord.DEFAULT_TTL, b"" + ) + params = {3: b"\x01\xbb"} + record = dns.https_records.HTTPSRecord(1, "example.org", params) + rr.data = dns.https_records.pack(record) + assert rr.https_ech is None + rr.https_ech = "dGVzdHN0cmluZwo=" + assert rr.https_ech == "dGVzdHN0cmluZwo=" + rr.https_ech = None + assert rr.https_ech is None + + def test_https_record_alpn(self): + rr = dns.ResourceRecord( + "test", dns.types.ANY, dns.classes.IN, dns.ResourceRecord.DEFAULT_TTL, b"" + ) + record = dns.https_records.HTTPSRecord(1, "example.org", {}) + rr.data = dns.https_records.pack(record) + + assert rr.https_alpn is None + assert rr.data == b"\x00\x01\x07example\x03org\x00" + + rr.https_alpn = [b"h2", b"h3"] + assert rr.https_alpn == (b"h2", b"h3") + assert rr.data == b"\x00\x01\x07example\x03org\x00\x00\x01\x00\x06\x02h2\x02h3" + + rr.https_alpn = None + assert rr.https_alpn is None + assert rr.data == b"\x00\x01\x07example\x03org\x00" + class TestMessage: def test_json(self): @@ -164,8 +209,24 @@ def assert_eq(m: dns.Message, b: bytes) -> None: + b"\x00\x00\x03\x84\x00H\x07ns-1707\tawsdns-21\x02co\x02uk\x00\x11awsdns-hostmaster\x06amazon\xc0\x19\x00" + b"\x00\x00\x01\x00\x00\x1c \x00\x00\x03\x84\x00\x12u\x00\x00\x01Q\x80\x00\x00)\x02\x00\x00\x00\x00\x00\x00\x00" ) - assert invalid_rr_domain_name.answers[0].data == b"\x99live\xc0\x12" - + assert ( + invalid_rr_domain_name.answers[0].data == b"\x99live\x06github\x03com\x00" + ) + valid_compressed_rr_data = dns.Message.unpack( + b"\x10}\x81\x80\x00\x01\x00\x01\x00\x00\x00\x01\x06google\x03com\x00\x00\x06\x00\x01\xc0\x0c\x00\x06\x00" + + b"\x01\x00\x00\x00\x0c\x00&\x03ns1\xc0\x0c\tdns-admin\xc0\x0c&~gw\x00\x00\x03\x84\x00\x00\x03\x84\x00" + + b"\x00\x07\x08\x00\x00\x00<\x00\x00)\x02\x00\x00\x00\x00\x00\x00\x00" + ) + assert ( + valid_compressed_rr_data.answers[0].data + == b"\x03ns1\x06google\x03com\x00\tdns-admin\x06google\x03com\x00&~gw\x00\x00\x03\x84\x00\x00\x03\x84\x00" + + b"\x00\x07\x08\x00\x00\x00<" + ) + A_record_data_contains_pointer_label = dns.Message.unpack( + b"\x98A\x81\x80\x00\x01\x00\x01\x00\x00\x00\x01\x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00" + + b"\x01\x00\x00\x00/\x00\x04\xd8:\xc4\xae\x00\x00)\x02\x00\x00\x00\x00\x00\x00\x00" + ) + assert A_record_data_contains_pointer_label.answers[0].data == b"\xd8:\xc4\xae" req = tutils.tdnsreq() for flag in ( "authoritative_answer", @@ -251,3 +312,9 @@ def test_match(self): def test_repr(self): f = tflow.tdnsflow() assert "DNSFlow" in repr(f) + + def test_question(self): + r = tflow.tdnsreq() + assert r.question + r.questions = [] + assert not r.question diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py index 5aa171f3e4..3815df4f77 100644 --- a/test/mitmproxy/test_flow.py +++ b/test/mitmproxy/test_flow.py @@ -51,6 +51,7 @@ def test_roundtrip(self): assert f2.get_state() == f.get_state() assert f2.request.data == f.request.data assert f2.marked + assert f2.comment == "test comment" def test_filter(self): sio = io.BytesIO() diff --git a/test/mitmproxy/test_http.py b/test/mitmproxy/test_http.py index fecf09e7ba..09cac17480 100644 --- a/test/mitmproxy/test_http.py +++ b/test/mitmproxy/test_http.py @@ -186,13 +186,13 @@ def test_authority(self): assert request.authority == "fussball" # Don't fail on garbage - request.data.authority = b"foo\xFF\x00bar" + request.data.authority = b"foo\xff\x00bar" assert request.authority.startswith("foo") assert request.authority.endswith("bar") # foo.bar = foo.bar should not cause any side effects. d = request.authority request.authority = d - assert request.data.authority == b"foo\xFF\x00bar" + assert request.data.authority == b"foo\xff\x00bar" def test_host_update_also_updates_header(self): request = treq() @@ -418,7 +418,7 @@ def test_get_urlencoded_form(self): request.headers["Content-Type"] = "application/x-www-form-urlencoded" assert list(request.urlencoded_form.items()) == [("foobar", "baz")] - request.raw_content = b"\xFF" + request.raw_content = b"\xff" assert len(request.urlencoded_form) == 1 def test_set_urlencoded_form(self): @@ -891,13 +891,13 @@ def _test_decoded_attr(message, attr): setattr(message, attr, "Non-Autorisé") assert getattr(message.data, attr) == b"Non-Autoris\xc3\xa9" # Don't fail on garbage - setattr(message.data, attr, b"FOO\xBF\x00BAR") + setattr(message.data, attr, b"FOO\xbf\x00BAR") assert getattr(message, attr).startswith("FOO") assert getattr(message, attr).endswith("BAR") # foo.bar = foo.bar should not cause any side effects. d = getattr(message, attr) setattr(message, attr, d) - assert getattr(message.data, attr) == b"FOO\xBF\x00BAR" + assert getattr(message.data, attr) == b"FOO\xbf\x00BAR" class TestMessageData: @@ -1135,7 +1135,7 @@ def test_guess_css_charset(self): assert "鏄庝集" in r.text def test_guess_latin_1(self): - r = tresp(content=b"\xF0\xE2") + r = tresp(content=b"\xf0\xe2") assert r.text == "ðâ" def test_none(self): @@ -1168,7 +1168,7 @@ def test_unknown_ce(self): def test_cannot_decode(self): r = tresp() r.headers["content-type"] = "text/html; charset=utf8" - r.raw_content = b"\xFF" + r.raw_content = b"\xff" with pytest.raises(ValueError): assert r.text @@ -1198,7 +1198,7 @@ def test_cannot_encode(self): r.headers["content-type"] = "text/html; charset=latin1" r.text = "\udcff" assert r.headers["content-type"] == "text/html; charset=utf-8" - assert r.raw_content == b"\xFF" + assert r.raw_content == b"\xff" def test_get_json(self): req = treq(content=None) diff --git a/test/mitmproxy/test_master.py b/test/mitmproxy/test_master.py index df7cea8360..04e0bb6005 100644 --- a/test/mitmproxy/test_master.py +++ b/test/mitmproxy/test_master.py @@ -1,4 +1,5 @@ import asyncio +import gc from mitmproxy.master import Master @@ -7,17 +8,26 @@ async def err(): raise RuntimeError -class TaskError: - def running(self): - # not assigned to anything - asyncio.create_task(err()) - - async def test_exception_handler(caplog_async): caplog_async.set_level("ERROR") - m = Master(None) - m.addons.add(TaskError()) - running = asyncio.create_task(m.run()) + + # start proxy master and let it initialize its exception handler + master = Master(None) + running = asyncio.create_task(master.run()) + await asyncio.sleep(0) + + # create a task with an unhandled exception... + task = asyncio.create_task(err()) + # make sure said task is run... + await asyncio.sleep(0) + + # and garbage-collected... + assert task + del task + gc.collect() + + # and ensure that this triggered a log entry. await caplog_async.await_log("Traceback") - m.shutdown() + + master.shutdown() await running diff --git a/test/mitmproxy/test_options.py b/test/mitmproxy/test_options.py index 777ab4dd18..dbaafe1a9d 100644 --- a/test/mitmproxy/test_options.py +++ b/test/mitmproxy/test_options.py @@ -1 +1,5 @@ -# TODO: write tests +from mitmproxy import options + + +def test_simple(): + assert options.Options() diff --git a/test/mitmproxy/test_version.py b/test/mitmproxy/test_version.py index 1e72ab4ed4..21c89ead12 100644 --- a/test/mitmproxy/test_version.py +++ b/test/mitmproxy/test_version.py @@ -16,8 +16,8 @@ def test_version(capsys): assert stdout.strip() == version.VERSION -def test_get_version(): - version.VERSION = "3.0.0rc2" +def test_get_version(monkeypatch): + monkeypatch.setattr(version, "VERSION", "3.0.0rc2") with mock.patch("subprocess.check_output") as m, mock.patch("subprocess.run") as m2: m2.return_value = True diff --git a/test/mitmproxy/test_websocket.py b/test/mitmproxy/test_websocket.py index 08117b0fb0..80cb3d9b3e 100644 --- a/test/mitmproxy/test_websocket.py +++ b/test/mitmproxy/test_websocket.py @@ -15,6 +15,13 @@ def test_state(self): f2 = http.HTTPFlow.from_state(f.get_state()) f2.set_state(f.get_state()) + def test_formatting(self): + tf = tflow.twebsocketflow().websocket + formatted_messages = tf._get_formatted_messages() + assert b"[OUTGOING] hello binary" in formatted_messages + assert b"[OUTGOING] hello text" in formatted_messages + assert b"[INCOMING] it's me" in formatted_messages + class TestWebSocketMessage: def test_basic(self): @@ -43,3 +50,14 @@ def test_text(self): _ = bin.text with pytest.raises(AttributeError, match="do not have a 'text' attribute."): bin.text = "bar" + + def test_message_formatting(self): + incoming_message = websocket.WebSocketMessage( + Opcode.BINARY, False, b"Test Incoming" + ) + outgoing_message = websocket.WebSocketMessage( + Opcode.BINARY, True, b"Test OutGoing" + ) + + assert incoming_message._format_ws_message() == b"[INCOMING] Test Incoming" + assert outgoing_message._format_ws_message() == b"[OUTGOING] Test OutGoing" diff --git a/test/mitmproxy/tools/console/conftest.py b/test/mitmproxy/tools/console/conftest.py index f17301f5f0..9a5fe85b80 100644 --- a/test/mitmproxy/tools/console/conftest.py +++ b/test/mitmproxy/tools/console/conftest.py @@ -30,7 +30,7 @@ def type(self, input: str) -> None: self.window.keypress(self.ui.get_cols_rows(), key) def screen_contents(self) -> str: - return b"\n".join(self.window.render((80, 24), True)._text_content()).decode() + return b"\n".join(self.window.render((80, 24), True).text).decode() @pytest.fixture diff --git a/test/mitmproxy/tools/console/test_master.py b/test/mitmproxy/tools/console/test_master.py index e69de29bb2..47651482c1 100644 --- a/test/mitmproxy/tools/console/test_master.py +++ b/test/mitmproxy/tools/console/test_master.py @@ -0,0 +1,30 @@ +from unittest.mock import Mock + + +def test_spawn_editor(monkeypatch, console): + text_data = "text" + binary_data = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" + + console.get_editor = Mock() + console.get_editor.return_value = "editor" + console.get_hex_editor = Mock() + console.get_hex_editor.return_value = "editor" + monkeypatch.setattr("subprocess.call", (lambda _: None)) + + console.loop = Mock() + console.loop.stop = Mock() + console.loop.start = Mock() + console.loop.draw_screen = Mock() + + console.spawn_editor(text_data) + console.get_editor.assert_called_once() + + console.spawn_editor(binary_data) + console.get_hex_editor.assert_called_once() + + +def test_get_hex_editor(monkeypatch, console): + test_editor = "hexedit" + monkeypatch.setattr("shutil.which", lambda x: x == test_editor) + editor = console.get_hex_editor() + assert editor == test_editor diff --git a/test/mitmproxy/tools/web/test_app.py b/test/mitmproxy/tools/web/test_app.py index 616e4c8e7a..eac14fa286 100644 --- a/test/mitmproxy/tools/web/test_app.py +++ b/test/mitmproxy/tools/web/test_app.py @@ -1,30 +1,24 @@ import gzip -import io +import importlib import json import logging -import textwrap -from collections.abc import Sequence -from contextlib import redirect_stdout from pathlib import Path -from typing import Optional from unittest import mock -from unittest.mock import Mock import pytest import tornado.testing from tornado import httpclient from tornado import websocket -from mitmproxy import certs +import mitmproxy_rs from mitmproxy import log from mitmproxy import options -from mitmproxy import optmanager -from mitmproxy.http import Headers -from mitmproxy.proxy.mode_servers import ServerInstance from mitmproxy.test import tflow from mitmproxy.tools.web import app from mitmproxy.tools.web import master as webmaster +here = Path(__file__).parent.absolute() + @pytest.fixture(scope="module") def no_tornado_logging(): @@ -41,118 +35,14 @@ def get_json(resp: httpclient.HTTPResponse): return json.loads(resp.body.decode()) -def test_generate_tflow_js(tdata): - tf_http = tflow.tflow(resp=True, err=True, ws=True) - tf_http.id = "d91165be-ca1f-4612-88a9-c0f8696f3e29" - tf_http.client_conn.id = "4a18d1a0-50a1-48dd-9aa6-d45d74282939" - tf_http.server_conn.id = "f087e7b2-6d0a-41a8-a8f0-e1a4761395f8" - tf_http.server_conn.certificate_list = [ - certs.Cert.from_pem( - Path( - tdata.path("mitmproxy/net/data/verificationcerts/self-signed.pem") - ).read_bytes() - ) - ] - tf_http.request.trailers = Headers(trailer="qvalue") - tf_http.response.trailers = Headers(trailer="qvalue") - tf_http.comment = "I'm a comment!" - - tf_tcp = tflow.ttcpflow(err=True) - tf_tcp.id = "2ea7012b-21b5-4f8f-98cd-d49819954001" - tf_tcp.client_conn.id = "8be32b99-a0b3-446e-93bc-b29982fe1322" - tf_tcp.server_conn.id = "e33bb2cd-c07e-4214-9a8e-3a8f85f25200" - - tf_udp = tflow.tudpflow(err=True) - tf_udp.id = "f9f7b2b9-7727-4477-822d-d3526e5b8951" - tf_udp.client_conn.id = "0a8833da-88e4-429d-ac54-61cda8a7f91c" - tf_udp.server_conn.id = "c49f9c2b-a729-4b16-9212-d181717e294b" - - tf_dns = tflow.tdnsflow(resp=True, err=True) - tf_dns.id = "5434da94-1017-42fa-872d-a189508d48e4" - tf_dns.client_conn.id = "0b4cc0a3-6acb-4880-81c0-1644084126fc" - tf_dns.server_conn.id = "db5294af-c008-4098-a320-a94f901eaf2f" - - # language=TypeScript - content = ( - "/** Auto-generated by test_app.py:test_generate_tflow_js */\n" - "import {HTTPFlow, TCPFlow, UDPFlow, DNSFlow} from '../../flow';\n" - "export function THTTPFlow(): Required {\n" - " return %s\n" - "}\n" - "export function TTCPFlow(): Required {\n" - " return %s\n" - "}\n" - "export function TUDPFlow(): Required {\n" - " return %s\n" - "}\n" - "export function TDNSFlow(): Required {\n" - " return %s\n" - "}\n" - % ( - textwrap.indent( - json.dumps(app.flow_to_json(tf_http), indent=4, sort_keys=True), " " - ), - textwrap.indent( - json.dumps(app.flow_to_json(tf_tcp), indent=4, sort_keys=True), " " - ), - textwrap.indent( - json.dumps(app.flow_to_json(tf_udp), indent=4, sort_keys=True), " " - ), - textwrap.indent( - json.dumps(app.flow_to_json(tf_dns), indent=4, sort_keys=True), " " - ), - ) - ) - content = content.replace(": null", ": undefined") - - ( - Path(__file__).parent / "../../../../web/src/js/__tests__/ducks/_tflow.ts" - ).write_bytes(content.encode()) - - -async def test_generate_options_js(): - o = options.Options() - m = webmaster.WebMaster(o) - opt: optmanager._Option - - def ts_type(t): - if t == bool: - return "boolean" - if t == str: - return "string" - if t == int: - return "number" - if t == Sequence[str]: - return "string[]" - if t == Optional[str]: - return "string | undefined" - if t == Optional[int]: - return "number | undefined" - raise RuntimeError(t) - - with redirect_stdout(io.StringIO()) as s: - print("/** Auto-generated by test_app.py:test_generate_options_js */") - - print("export interface OptionsState {") - for _, opt in sorted(m.options.items()): - print(f" {opt.name}: {ts_type(opt.typespec)};") - print("}") - print("") - print("export type Option = keyof OptionsState;") - print("") - print("export const defaultState: OptionsState = {") - for _, opt in sorted(m.options.items()): - print( - f" {opt.name}: {json.dumps(opt.default)},".replace( - ": null", ": undefined" - ) - ) - print("};") - - ( - Path(__file__).parent / "../../../../web/src/js/ducks/_options_gen.ts" - ).write_bytes(s.getvalue().encode()) - await m.done() +@pytest.mark.parametrize("filename", list((here / "../../../../web/gen").glob("*.py"))) +async def test_generated_files(filename): + mod = importlib.import_module(f"web.gen.{filename.stem}") + expected = await mod.make() + actual = mod.filename.read_text().replace("\r\n", "\n") + assert ( + actual == expected + ), f"{mod.filename} must be regenerated by running {filename.resolve()}." @pytest.mark.usefixtures("no_tornado_logging", "tdata") @@ -176,24 +66,6 @@ async def make_master() -> webmaster.WebMaster: m.view.add([tflow.tflow(err=True)]) m.events._add_log(log.LogEntry("test log", "info")) m.events.done() - si1 = ServerInstance.make("regular", m.proxyserver) - sock1 = Mock() - sock1.getsockname.return_value = ("127.0.0.1", 8080) - sock2 = Mock() - sock2.getsockname.return_value = ("::1", 8080) - server = Mock() - server.sockets = [sock1, sock2] - si1._servers = [server] - si2 = ServerInstance.make("reverse:example.com", m.proxyserver) - si2.last_exception = RuntimeError("I failed somehow.") - si3 = ServerInstance.make("socks5", m.proxyserver) - m.proxyserver.servers._instances.update( - { - si1.mode: si1, - si2.mode: si2, - si3.mode: si3, - } - ) self.master = m self.view = m.view self.events = m.events @@ -308,6 +180,7 @@ def test_flow_update(self): "content": "resp", }, "marked": ":red_circle:", + "comment": "I'm a modified comment!", } assert self.put_json("/flows/42", upd).code == 200 assert f.request.method == "PATCH" @@ -318,6 +191,7 @@ def test_flow_update(self): assert f.response.status_code == 404 assert f.response.headers["bar"] == "baz" assert f.response.text == "resp" + assert f.comment == "I'm a modified comment!" upd = { "request": { @@ -498,31 +372,6 @@ def test_option_update(self): def test_option_save(self): assert self.fetch("/options/save", method="POST").code == 200 - def test_generate_state_js(self): - resp = self.fetch("/state") - assert resp.code == 200 - data = json.loads(resp.body) - data.update(available=True) - data["contentViews"] = ["Auto", "Raw"] - data["version"] = "1.2.3" - - # language=TypeScript - content = ( - "/** Auto-generated by test_app.py:test_generate_state_js */\n" - "import {BackendState} from '../../ducks/backendState';\n" - "export function TBackendState(): Required {\n" - " return %s\n" - "}\n" - % textwrap.indent( - json.dumps(data, indent=4, sort_keys=True), " " - ).lstrip() - ) - - ( - Path(__file__).parent - / "../../../../web/src/js/__tests__/ducks/_tbackendstate.ts" - ).write_bytes(content.encode()) - def test_err(self): with mock.patch("mitmproxy.tools.web.app.IndexHandler.get") as f: f.side_effect = RuntimeError @@ -555,3 +404,32 @@ def test_websocket(self): # trigger on_close by opening a second connection. ws_client2 = yield websocket.websocket_connect(ws_url) ws_client2.close() + + def test_process_list(self): + try: + mitmproxy_rs.process_info.active_executables() + except NotImplementedError: + pytest.skip( + "mitmproxy_rs.process_info.active_executables not available on this platform." + ) + resp = self.fetch("/processes") + assert resp.code == 200 + assert get_json(resp) + + def test_process_icon(self): + try: + mitmproxy_rs.process_info.executable_icon("invalid") + except NotImplementedError: + pytest.skip( + "mitmproxy_rs.process_info.executable_icon not available on this platform." + ) + except Exception: + pass + resp = self.fetch("/executable-icon") + assert resp.code == 400 + assert "Missing 'path' parameter." in resp.body.decode() + + resp = self.fetch("/executable-icon?path=invalid_path") + assert resp.code == 200 + assert resp.headers["Content-Type"] == "image/png" + assert resp.body == app.TRANSPARENT_PNG diff --git a/test/mitmproxy/tools/web/test_master.py b/test/mitmproxy/tools/web/test_master.py index ee0225754a..e956b73d4c 100644 --- a/test/mitmproxy/tools/web/test_master.py +++ b/test/mitmproxy/tools/web/test_master.py @@ -1,5 +1,4 @@ import asyncio -from unittest.mock import MagicMock import pytest @@ -8,8 +7,11 @@ async def test_reuse(): + async def handler(r, w): + pass + server = await asyncio.start_server( - MagicMock(), host="127.0.0.1", port=0, reuse_address=False + handler, host="127.0.0.1", port=0, reuse_address=False ) port = server.sockets[0].getsockname()[1] master = WebMaster(Options(), with_termlog=False) @@ -18,3 +20,6 @@ async def test_reuse(): with pytest.raises(OSError, match=f"--set web_port={port + 2}"): await master.running() server.close() + # tornado registers some callbacks, + # we want to run them to avoid fatal warnings. + await asyncio.sleep(0) diff --git a/test/mitmproxy/tools/web/test_web_columns.py b/test/mitmproxy/tools/web/test_web_columns.py new file mode 100644 index 0000000000..6bb85f21f2 --- /dev/null +++ b/test/mitmproxy/tools/web/test_web_columns.py @@ -0,0 +1,5 @@ +from mitmproxy.tools.web.web_columns import AVAILABLE_WEB_COLUMNS + + +def test_web_columns(): + assert isinstance(AVAILABLE_WEB_COLUMNS, list) diff --git a/test/mitmproxy/utils/test_asyncio_utils.py b/test/mitmproxy/utils/test_asyncio_utils.py index 1b59da8b62..05891221b3 100644 --- a/test/mitmproxy/utils/test_asyncio_utils.py +++ b/test/mitmproxy/utils/test_asyncio_utils.py @@ -1,4 +1,8 @@ import asyncio +import gc +import sys + +import pytest from mitmproxy.utils import asyncio_utils @@ -8,10 +12,52 @@ async def ttask(): await asyncio.sleep(999) -async def test_simple(): +async def test_simple(monkeypatch): + monkeypatch.setenv("PYTEST_CURRENT_TEST", "test_foo") task = asyncio_utils.create_task(ttask(), name="ttask", client=("127.0.0.1", 42313)) - assert asyncio_utils.task_repr(task) == "127.0.0.1:42313: ttask (age: 0s)" + assert ( + asyncio_utils.task_repr(task) + == "127.0.0.1:42313: ttask [created in test_foo] (age: 0s)" + ) await asyncio.sleep(0) assert "newname" in asyncio_utils.task_repr(task) delattr(task, "created") assert asyncio_utils.task_repr(task) + + +async def _raise(): + raise RuntimeError() + + +async def test_install_exception_handler(): + e = asyncio.Event() + with asyncio_utils.install_exception_handler(lambda *_, **__: e.set()): + t = asyncio.create_task(_raise()) + await asyncio.sleep(0) + assert t.done() + del t + gc.collect() + await e.wait() + + +async def test_eager_task_factory(): + x = False + + async def task(): + nonlocal x + x = True + + # assert that override works... + assert type(asyncio.get_event_loop_policy()) is asyncio.DefaultEventLoopPolicy + + with asyncio_utils.set_eager_task_factory(): + _ = asyncio.create_task(task()) + if sys.version_info >= (3, 12): + # ...and the context manager is effective + assert x + + +@pytest.fixture() +def event_loop_policy(request): + # override EagerTaskCreationEventLoopPolicy from top-level conftest + return asyncio.DefaultEventLoopPolicy() diff --git a/test/mitmproxy/utils/test_strutils.py b/test/mitmproxy/utils/test_strutils.py index f5b2894ac0..c1fae9d8e7 100644 --- a/test/mitmproxy/utils/test_strutils.py +++ b/test/mitmproxy/utils/test_strutils.py @@ -79,8 +79,8 @@ def test_escaped_str_to_bytes(): def test_is_mostly_bin(): - assert not strutils.is_mostly_bin(b"foo\xFF") - assert strutils.is_mostly_bin(b"foo" + b"\xFF" * 10) + assert not strutils.is_mostly_bin(b"foo\xff") + assert strutils.is_mostly_bin(b"foo" + b"\xff" * 10) assert not strutils.is_mostly_bin("") diff --git a/web/README.md b/web/README.md index 4c242ac2f8..7cb616ca17 100644 --- a/web/README.md +++ b/web/README.md @@ -1,7 +1,7 @@ # Quick Start - Install mitmproxy as described in [`../CONTRIBUTING.md`](../CONTRIBUTING.md) -- Run `node --version` to make sure that you have at least Node.js 14 or above. If you are on **Ubuntu <= 20.04**, you +- Run `node --version` to make sure that you have at least Node.js 18 or above. If you are on **Ubuntu <= 22.04**, you need to [upgrade](https://github.com/nodesource/distributions/blob/master/README.md#installation-instructions). - Run `cd mitmproxy/web` to change to the directory with package.json diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs new file mode 100644 index 0000000000..e9d6300699 --- /dev/null +++ b/web/eslint.config.mjs @@ -0,0 +1,54 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; +import pluginReactConfig from "eslint-plugin-react/configs/recommended.js"; + +export default [ + { files: ["**/*.{ts,tsx}"] }, + { languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } }, + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + pluginReactConfig, + { + rules: { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "after-used", + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "one-var": ["error", { const: "never", let: "consecutive" }], + }, + settings: { + react: { + version: "detect", + }, + }, + }, + { + files: ["src/**/*Spec.{ts,tsx}"], + rules: { + "prefer-const": "off", + }, + }, + { + files: ["jest.config.js", "gulpfile.js"], + languageOptions: { globals: globals.node }, + }, + { + files: ["src/**/*.{js,jsx}"], + rules: { + "no-restricted-syntax": [ + "error", + { + selector: "*", + message: "Only TypeScript (ts, tsx) files are allowed.", + }, + ], + }, + }, +]; diff --git a/web/gen/all b/web/gen/all new file mode 100755 index 0000000000..f314d2e1db --- /dev/null +++ b/web/gen/all @@ -0,0 +1,9 @@ +#!/bin/bash + +set -euxo pipefail + +script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +for file in "$script_dir"/*.py; do + "$file" +done diff --git a/web/gen/backend_consts.py b/web/gen/backend_consts.py new file mode 100755 index 0000000000..40ec0e6ff0 --- /dev/null +++ b/web/gen/backend_consts.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +import asyncio +import typing +from pathlib import Path + +from mitmproxy.proxy.mode_specs import ReverseMode + +here = Path(__file__).parent.absolute() + +filename = here / "../src/js/backends/consts.ts" + + +async def make() -> str: + data = { + "protocols": typing.get_args(typing.get_type_hints(ReverseMode)["scheme"]), + } + + protocols = ",\n ".join( + f'{protocol.upper()} = "{protocol.lower()}"' for protocol in data["protocols"] + ) + + # language=TypeScript + content = ( + "/** Auto-generated by web/gen/backend_consts.py */\n" + "export enum ReverseProxyProtocols {\n" + f" {protocols},\n" + "}\n" + ) + + return content + + +if __name__ == "__main__": + filename.write_bytes(asyncio.run(make()).encode()) diff --git a/web/gen/options_js.py b/web/gen/options_js.py new file mode 100755 index 0000000000..2bd1ddbc37 --- /dev/null +++ b/web/gen/options_js.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import asyncio +import io +import json +from collections.abc import Sequence +from contextlib import redirect_stdout +from pathlib import Path + +from mitmproxy import options +from mitmproxy import optmanager +from mitmproxy.tools.web import master + +here = Path(__file__).parent.absolute() + +filename = here / "../src/js/ducks/_options_gen.ts" + + +def _ts_type(t): + if t is bool: + return "boolean" + if t is str: + return "string" + if t is int: + return "number" + if t == Sequence[str]: + return "string[]" + if t == str | None: + return "string | undefined" + if t == int | None: + return "number | undefined" + raise RuntimeError(t) + + +async def make() -> str: + o = options.Options() + m = master.WebMaster(o) + opt: optmanager._Option + + with redirect_stdout(io.StringIO()) as s: + print("/** Auto-generated by web/gen/options_js.py */") + + print("export interface OptionsState {") + for _, opt in sorted(m.options.items()): + print(f" {opt.name}: {_ts_type(opt.typespec)};") + print("}") + print("") + print("export type Option = keyof OptionsState;") + print("") + print("export const defaultState: OptionsState = {") + for _, opt in sorted(m.options.items()): + print( + f" {opt.name}: {json.dumps(opt.default)},".replace( + ": null", ": undefined" + ) + ) + print("};") + + await m.done() + return s.getvalue() + + +if __name__ == "__main__": + filename.write_bytes(asyncio.run(make()).encode()) diff --git a/web/gen/state_js.py b/web/gen/state_js.py new file mode 100755 index 0000000000..187b53ea71 --- /dev/null +++ b/web/gen/state_js.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import asyncio +import json +import textwrap +from pathlib import Path +from unittest.mock import Mock + +from mitmproxy import options +from mitmproxy.proxy.mode_servers import ServerInstance +from mitmproxy.tools.web import app +from mitmproxy.tools.web import master + +here = Path(__file__).parent.absolute() + +filename = here / "../src/js/__tests__/ducks/_tbackendstate.ts" + + +async def make() -> str: + o = options.Options() + m = master.WebMaster(o) + + si1 = ServerInstance.make("regular", m.proxyserver) + sock1 = Mock() + sock1.getsockname.return_value = ("127.0.0.1", 8080) + sock2 = Mock() + sock2.getsockname.return_value = ("::1", 8080) + server = Mock() + server.sockets = [sock1, sock2] + si1._servers = [server] + si2 = ServerInstance.make("reverse:example.com", m.proxyserver) + si2.last_exception = RuntimeError("I failed somehow.") + si3 = ServerInstance.make("socks5", m.proxyserver) + m.proxyserver.servers._instances.update( + { + si1.mode: si1, + si2.mode: si2, + si3.mode: si3, + } + ) + + data = app.State.get_json(m) + await m.done() + + data.update(available=True) + data["contentViews"] = ["Auto", "Raw"] + data["version"] = "1.2.3" + data["platform"] = "darwin" + + # language=TypeScript + content = ( + "/** Auto-generated by web/gen/state_js.py */\n" + "import {BackendState} from '../../ducks/backendState';\n" + "export function TBackendState(): Required {\n" + " return %s\n" + "}\n" + % textwrap.indent(json.dumps(data, indent=4, sort_keys=True), " ").lstrip() + ) + + return content + + +if __name__ == "__main__": + filename.write_bytes(asyncio.run(make()).encode()) diff --git a/web/gen/tflow_js.py b/web/gen/tflow_js.py new file mode 100755 index 0000000000..32d71c84d0 --- /dev/null +++ b/web/gen/tflow_js.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +import asyncio +import json +import textwrap +from pathlib import Path + +from mitmproxy import certs +from mitmproxy.http import Headers +from mitmproxy.test import tflow +from mitmproxy.tools.web import app + +here = Path(__file__).parent.absolute() + +filename = here / "../src/js/__tests__/ducks/_tflow.ts" + + +async def make() -> str: + tf_http = tflow.tflow(resp=True, err=True, ws=True) + tf_http.id = "d91165be-ca1f-4612-88a9-c0f8696f3e29" + tf_http.client_conn.id = "4a18d1a0-50a1-48dd-9aa6-d45d74282939" + tf_http.server_conn.id = "f087e7b2-6d0a-41a8-a8f0-e1a4761395f8" + tf_http.server_conn.certificate_list = [ + certs.Cert.from_pem( + ( + here / "../../test/mitmproxy/net/data/verificationcerts/self-signed.pem" + ).read_bytes() + ) + ] + tf_http.request.trailers = Headers(trailer="qvalue") + tf_http.response.trailers = Headers(trailer="qvalue") + tf_http.comment = "I'm a comment!" + + tf_tcp = tflow.ttcpflow(err=True) + tf_tcp.id = "2ea7012b-21b5-4f8f-98cd-d49819954001" + tf_tcp.client_conn.id = "8be32b99-a0b3-446e-93bc-b29982fe1322" + tf_tcp.server_conn.id = "e33bb2cd-c07e-4214-9a8e-3a8f85f25200" + + tf_udp = tflow.tudpflow(err=True) + tf_udp.id = "f9f7b2b9-7727-4477-822d-d3526e5b8951" + tf_udp.client_conn.id = "0a8833da-88e4-429d-ac54-61cda8a7f91c" + tf_udp.server_conn.id = "c49f9c2b-a729-4b16-9212-d181717e294b" + + tf_dns = tflow.tdnsflow(resp=True, err=True) + tf_dns.id = "5434da94-1017-42fa-872d-a189508d48e4" + tf_dns.client_conn.id = "0b4cc0a3-6acb-4880-81c0-1644084126fc" + tf_dns.server_conn.id = "db5294af-c008-4098-a320-a94f901eaf2f" + + # language=TypeScript + content = ( + "/** Auto-generated by web/gen/tflow_js.py */\n" + "import {HTTPFlow, TCPFlow, UDPFlow, DNSFlow} from '../../flow';\n" + "export function THTTPFlow(): Required {\n" + " return %s\n" + "}\n" + "export function TTCPFlow(): Required {\n" + " return %s\n" + "}\n" + "export function TUDPFlow(): Required {\n" + " return %s\n" + "}\n" + "export function TDNSFlow(): Required {\n" + " return %s\n" + "}\n" + % ( + textwrap.indent( + json.dumps(app.flow_to_json(tf_http), indent=4, sort_keys=True), " " + ), + textwrap.indent( + json.dumps(app.flow_to_json(tf_tcp), indent=4, sort_keys=True), " " + ), + textwrap.indent( + json.dumps(app.flow_to_json(tf_udp), indent=4, sort_keys=True), " " + ), + textwrap.indent( + json.dumps(app.flow_to_json(tf_dns), indent=4, sort_keys=True), " " + ), + ) + ) + content = content.replace(": null", ": undefined") + return content + + +if __name__ == "__main__": + filename.write_bytes(asyncio.run(make()).encode()) diff --git a/web/gen/web_columns.py b/web/gen/web_columns.py new file mode 100755 index 0000000000..7a2c613911 --- /dev/null +++ b/web/gen/web_columns.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import asyncio +import json +import re +from pathlib import Path + +here = Path(__file__).parent.absolute() + +input_filename = here / "../src/js/components/FlowTable/FlowColumns.tsx" +filename = here / "../../mitmproxy/tools/web/web_columns.py" + + +def extract_columns() -> list: + # Read the Typescript file content + input_file_content = input_filename.read_text() + + pattern = r"//\s*parsed by web/gen/web_columns\s*\n([\s\w,]+)" + + match = re.search(pattern, input_file_content, re.MULTILINE) + + columns_str = match.group(1) + + columns = [col.strip() for col in columns_str.split(",") if col.strip()] + + return columns + + +async def make() -> str: + available_web_columns = extract_columns() + + # language=Python + content = ( + "# Auto-generated by web/gen/web_columns.py\n" + f"AVAILABLE_WEB_COLUMNS = {json.dumps(available_web_columns, indent=4)}" + ) + + return content + + +if __name__ == "__main__": + filename.write_bytes(asyncio.run(make()).encode()) diff --git a/web/gulpfile.js b/web/gulpfile.js index e322e818c8..f59de42b36 100644 --- a/web/gulpfile.js +++ b/web/gulpfile.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const gulp = require("gulp"); const gulpEsbuild = require("gulp-esbuild"); const less = require("gulp-less"); @@ -55,7 +56,7 @@ function esbuild(dev) { minify: !dev, keepNames: true, bundle: true, - }) + }), ) .pipe(gulp.dest("../mitmproxy/tools/web/static")) .pipe(livereload({ auto: false })); @@ -77,7 +78,7 @@ const copy_src = [ function copy() { return gulp - .src(copy_src, { base: "src/" }) + .src(copy_src, { base: "src/", encoding: false }) .pipe(gulp.dest("../mitmproxy/tools/web/static")); } @@ -99,9 +100,10 @@ function peg() { .pipe( replace( "module.exports = ", - 'import * as flowutils from "../flow/utils"\n' + - "export default " - ) + "/* eslint-disable */\n" + + 'import * as flowutils from "../flow/utils"\n' + + "export default ", + ), ) .pipe(gulp.dest("src/")); } @@ -112,7 +114,7 @@ const dev = gulp.parallel( styles_app_dev, peg, scripts_dev, - templates + templates, ); const prod = gulp.parallel( @@ -121,7 +123,7 @@ const prod = gulp.parallel( styles_app_prod, peg, scripts_prod, - templates + templates, ); exports.dev = dev; diff --git a/web/package-lock.json b/web/package-lock.json index f8ba1016a4..442ffbfaf5 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,8749 +1,13910 @@ { "name": "mitmproxy", + "lockfileVersion": 3, "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "packages": { + "": { + "name": "mitmproxy", + "dependencies": { + "@popperjs/core": "^2.11.8", + "@reduxjs/toolkit": "^2.2.5", + "bootstrap": "^3.4.1", + "classnames": "^2.3.1", + "codemirror": "^5.62.3", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "qrcode": "^1.5.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-popper": "^2.2.5", + "react-redux": "^9.1.2", + "stable": "^0.1.8" + }, + "devDependencies": { + "@eslint/js": "^9.6.0", + "@testing-library/dom": "^10.3.1", + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^16.0.0", + "@testing-library/user-event": "^14.5.2", + "@types/jest": "^29.5.12", + "@types/redux-mock-store": "^1.0.3", + "esbuild": "^0.23.0", + "esbuild-jest": "^0.5.0", + "eslint": "^8.57.0", + "eslint-plugin-react": "^7.34.3", + "globals": "^15.8.0", + "gulp": "^5.0.0", + "gulp-clean-css": "^4.3.0", + "gulp-esbuild": "^0.12.0", + "gulp-less": "^5.0.0", + "gulp-livereload": "^4.0.2", + "gulp-notify": "^4.0.0", + "gulp-peg": "^0.2.0", + "gulp-plumber": "^1.2.1", + "gulp-replace": "^1.1.3", + "gulp-sourcemaps": "^3.0.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-fetch-mock": "^3.0.3", + "prettier": "3.3.2", + "react-test-renderer": "^18.3.1", + "redux-mock-store": "^1.5.4", + "through2": "^4.0.2", + "typescript": "^5.5.3", + "typescript-eslint": "^7.15.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" } }, - "@babel/compat-data": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.5.tgz", - "integrity": "sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w==", - "dev": true + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/core": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.3.tgz", - "integrity": "sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg==", + "node_modules/@babel/compat-data": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.3", - "@babel/helper-compilation-targets": "^7.13.16", - "@babel/helper-module-transforms": "^7.14.2", - "@babel/helpers": "^7.14.0", - "@babel/parser": "^7.14.3", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.2", - "@babel/types": "^7.14.2", - "convert-source-map": "^1.7.0", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "@babel/generator": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz", - "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==", + "node_modules/@babel/generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "dev": true, - "requires": { - "@babel/types": "^7.14.2", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-compilation-targets": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", - "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", "dev": true, - "requires": { - "@babel/compat-data": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" + "dependencies": { + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "@babel/parser": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.6.tgz", - "integrity": "sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==", - "dev": true - }, - "@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" - } - }, - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - } + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - } + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - } + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-member-expression-to-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.5.tgz", - "integrity": "sha512-UxUeEYPrqH1Q/k0yRku1JE7dyfyehNwT6SVkMHvYvPDv4+uu627VXBckVj891BO8ruKBkiDoGnZf4qPDD8abDQ==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - } + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - } + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "@babel/helper-module-transforms": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz", - "integrity": "sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", + "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.14.0", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.2", - "@babel/types": "^7.14.2" + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - } + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helper-replace-supers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", - "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.14.5", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "@babel/generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", - "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/parser": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.6.tgz", - "integrity": "sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==", - "dev": true - }, - "@babel/traverse": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.5.tgz", - "integrity": "sha512-G3BiS15vevepdmFqmUc9X+64y0viZYygubAMO8SvBmKARuF6CPSZtH4Ng9vi/lrWlZFGe3FWdXNy835akH8Glg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "node_modules/@babel/helper-string-parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "dev": true, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, - "requires": { - "@babel/types": "^7.13.12" + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - } + "node_modules/@babel/helper-validator-option": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "dev": true, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-validator-identifier": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", - "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", - "dev": true + "node_modules/@babel/helpers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helpers": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", - "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "requires": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "dependencies": { + "color-convert": "^1.9.0" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "@babel/generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", - "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/parser": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.6.tgz", - "integrity": "sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==", - "dev": true - }, - "@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" - } - }, - "@babel/traverse": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.5.tgz", - "integrity": "sha512-G3BiS15vevepdmFqmUc9X+64y0viZYygubAMO8SvBmKARuF6CPSZtH4Ng9vi/lrWlZFGe3FWdXNy835akH8Glg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.14.5", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" } }, - "@babel/parser": { - "version": "7.14.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.4.tgz", - "integrity": "sha512-ArliyUsWDUqEGfWcmzpGUzNfLxTdTp6WU4IuP6QFSp9gGfWS6boxFCkJSJ/L4+RG8z/FnIU3WxCk6hPL9SSWeA==", + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "@babel/plugin-syntax-async-generators": { + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-bigint": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-class-properties": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-import-meta": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-json-strings": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-logical-assignment-operators": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-nullish-coalescing-operator": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-numeric-separator": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-object-rest-spread": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-optional-catch-binding": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-optional-chaining": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-top-level-await": { + "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, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true - } + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-typescript": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", - "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - }, "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz", - "integrity": "sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", + "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.14.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-simple-access": "^7.13.12", - "babel-plugin-dynamic-import-node": "^2.3.3" + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/runtime": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", - "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", - "requires": { - "regenerator-runtime": "^0.13.4" + "node_modules/@babel/runtime": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/runtime-corejs3": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz", - "integrity": "sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A==", + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, - "requires": { - "core-js-pure": "^3.16.0", - "regenerator-runtime": "^0.13.4" + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@babel/traverse": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", - "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", + "node_modules/@babel/traverse/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, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.2", - "@babel/helper-function-name": "^7.14.2", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.14.2", - "@babel/types": "^7.14.2", - "debug": "^4.1.0", - "globals": "^11.1.0" + "engines": { + "node": ">=4" } }, - "@babel/types": { - "version": "7.14.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.4.tgz", - "integrity": "sha512-lCj4aIs0xUefJFQnwwQv2Bxg7Omd6bgquZ6LGC+gGMh6/s5qDVfjuCMlDmYQ15SLsWHd9n+X3E75lKIhl5Lkiw==", + "node_modules/@babel/types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", + "dependencies": { + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@bcoe/v8-coverage": { + "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 }, - "@cnakazawa/watch": { + "node_modules/@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", "dev": true, - "requires": { + "dependencies": { "exec-sh": "^0.3.2", "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" } }, - "@gulp-sourcemaps/identity-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", - "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==", + "node_modules/@cnakazawa/watch/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "requires": { - "acorn": "^6.4.1", - "normalize-path": "^3.0.0", - "postcss": "^7.0.16", - "source-map": "^0.6.0", - "through2": "^3.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "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 - }, - "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@gulp-sourcemaps/map-sources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "requires": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" } }, - "@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==", + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], "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": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "@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": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.6.tgz", - "integrity": "sha512-fMlIBocSHPZ3JxgWiDNW/KPj6s+YRd0hicb33IrmelCcjXo/pXPwvuiKFmZz+XuqI/1u7nbUK10zSsWL/1aegg==", + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.0.6", - "jest-util": "^27.0.6", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "@jest/core": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.6.tgz", - "integrity": "sha512-SsYBm3yhqOn5ZLJCtccaBcvD/ccTLCeuDv8U41WJH/V1MW5eKUkeMHT9U+Pw/v1m1AIWlnIW/eM2XzQr0rEmow==", + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/reporters": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.0.6", - "jest-config": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-resolve-dependencies": "^27.0.6", - "jest-runner": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "jest-watcher": "^27.0.6", - "micromatch": "^4.0.4", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "@jest/environment": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.6.tgz", - "integrity": "sha512-4XywtdhwZwCpPJ/qfAkqExRsERW+UaoSRStSHCCiQTUpoYdLukj+YJbQSFrZjhlUDRZeNiU9SFH0u7iNimdiIg==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], "dev": true, - "requires": { - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "@jest/fake-timers": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.6.tgz", - "integrity": "sha512-sqd+xTWtZ94l3yWDKnRTdvTeZ+A/V7SSKrxsrOKSqdyddb9CeNRF8fbhAU0D7ZJBpTTW2nbp6MftmKJDZfW2LQ==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@sinonjs/fake-timers": "^7.0.2", - "@types/node": "*", - "jest-message-util": "^27.0.6", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } - } - }, - "@jest/globals": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.6.tgz", - "integrity": "sha512-DdTGCP606rh9bjkdQ7VvChV18iS7q0IMJVP1piwTWyWskol4iqcVwthZmoJEf7obE1nc34OpIyoVGPeqLC+ryw==", - "dev": true, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/types": "^27.0.6", - "expect": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "@jest/reporters": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.6.tgz", - "integrity": "sha512-TIkBt09Cb2gptji3yJXb3EE+eVltW6BjO7frO7NEfjI9vSIYoISi5R3aI3KpEDXlB1xwB+97NXIqz84qYeYsfA==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" } }, - "@jest/source-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", - "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" } }, - "@jest/test-result": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.6.tgz", - "integrity": "sha512-ja/pBOMTufjX4JLEauLxE3LQBPaI2YjGFtXexRAjt1I/MbfNlMx0sytSX3tn5hSLzQsR3Qy2rd0hc1BWojtj9w==", + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@jest/test-sequencer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.6.tgz", - "integrity": "sha512-bISzNIApazYOlTHDum9PwW22NOyDa6VI31n6JucpjTVM0jD6JDgqEZ9+yn575nDdPF0+4csYDxNNW13NvFQGZA==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], "dev": true, - "requires": { - "@jest/test-result": "^27.0.6", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-runtime": "^27.0.6" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@jest/transform": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.6.tgz", - "integrity": "sha512-rj5Dw+mtIcntAUnMlW/Vju5mr73u8yg+irnHwzgtgoeI6cCPOvUwQ0D1uQtc/APmWgvRweEb1g05pkUpxH3iCA==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.0.6", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-util": "^27.0.6", - "micromatch": "^4.0.4", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@jest/types": { - "version": "27.0.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", - "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@popperjs/core": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.3.tgz", - "integrity": "sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ==" - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], "dev": true, - "requires": { - "type-detect": "4.0.8" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@sinonjs/fake-timers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", - "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@testing-library/dom": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.1.0.tgz", - "integrity": "sha512-kmW9alndr19qd6DABzQ978zKQ+J65gU2Rzkl8hriIetPnwpesRaK4//jEQyYh8fEALmGhomD/LBQqt+o+DL95Q==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@testing-library/jest-dom": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", - "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], "dev": true, - "requires": { - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^4.2.2", - "chalk": "^3.0.0", - "css": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "requires": { - "min-indent": "^1.0.0" - } - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@testing-library/react": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.0.0.tgz", - "integrity": "sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==", + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "@testing-library/user-event": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.2.1.tgz", - "integrity": "sha512-cczlgVl+krjOb3j1625usarNEibI0IFRJrSWX9UsJ1HKYFgCQv9Nb7QAipUDXl3Xdz8NDTsiS78eAkPSxlzTlw==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "@babel/runtime": "^7.12.5" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "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" + ], "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "@babel/types": "^7.0.0" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" } }, - "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" } }, - "@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], "dev": true, - "requires": { - "@babel/types": "^7.3.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "@types/expect": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz", - "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", - "dev": true - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], "dev": true, - "requires": { - "@types/node": "*" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "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==", + "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, - "requires": { - "@types/istanbul-lib-coverage": "*" + "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" } }, - "@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==", + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "@types/jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", - "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", + "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, - "requires": { - "jest-diff": "^27.0.0", - "pretty-format": "^27.0.0" + "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" } }, - "@types/node": { - "version": "15.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", - "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==", - "dev": true - }, - "@types/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", + "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 }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" - }, - "@types/react": { - "version": "17.0.11", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.11.tgz", - "integrity": "sha512-yFRQbD+whVonItSk7ZzP/L+gPTJVBkL/7shLEF+i9GC/1cV3JmUxEQz6+9ylhUpWSDuqo1N9qEvqS6vTj4USUA==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-redux": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz", - "integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==", - "requires": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - }, + "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": { - "redux": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", - "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", - "requires": { - "@babel/runtime": "^7.9.2" - } - } + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@types/redux-mock-store": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/redux-mock-store/-/redux-mock-store-1.0.3.tgz", - "integrity": "sha512-Wqe3tJa6x9MxMN4DJnMfZoBRBRak1XTPklqj4qkVm5VBpZnC8PSADf4kLuFQ9NAdHaowfWoEeUMz7NWc2GMtnA==", + "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, - "requires": { - "redux": "^4.0.5" + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "@types/scheduler": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", - "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" - }, - "@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/testing-library__jest-dom": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.1.tgz", - "integrity": "sha512-Gk9vaXfbzc5zCXI9eYE9BI5BNHEp4D3FWjgqBE/ePGYElLAP+KvxBcsdkwfIVvezs605oiyd/VrpiHe3Oeg+Aw==", + "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, - "requires": { - "@types/jest": "*" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@types/vinyl": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.4.tgz", - "integrity": "sha512-2o6a2ixaVI2EbwBPg1QYLGQoHK56p/8X/sGfKbFC8N6sY9lfjsMf/GprtkQkSya0D4uRiutRZ2BWj7k3JvLsAQ==", + "node_modules/@eslint/js": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", + "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", "dev": true, - "requires": { - "@types/expect": "^1.20.4", - "@types/node": "*" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "@types/yargs": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", - "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "node_modules/@gulp-sourcemaps/identity-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", + "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==", "dev": true, - "requires": { - "@types/yargs-parser": "*" + "dependencies": { + "acorn": "^6.4.1", + "normalize-path": "^3.0.0", + "postcss": "^7.0.16", + "source-map": "^0.6.0", + "through2": "^3.0.1" + }, + "engines": { + "node": ">= 0.10" } }, - "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", - "dev": true - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "acorn": { + "node_modules/@gulp-sourcemaps/identity-map/node_modules/acorn": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "bin": { + "acorn": "bin/acorn" }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } + "engines": { + "node": ">=0.4.0" } }, - "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==", - "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==", + "node_modules/@gulp-sourcemaps/identity-map/node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, - "requires": { - "debug": "4" + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" } }, - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "node_modules/@gulp-sourcemaps/map-sources": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", + "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", "dev": true, - "requires": { - "ansi-wrap": "^0.1.0" + "dependencies": { + "normalize-path": "^2.0.1", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" } }, - "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" - } + "node_modules/@gulp-sourcemaps/map-sources/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "node_modules/@gulp-sourcemaps/map-sources/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, - "requires": { - "ansi-wrap": "0.1.0" + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - }, - "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" - }, + "node_modules/@gulp-sourcemaps/map-sources/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, "dependencies": { - "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==" - } + "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" } }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "node_modules/@gulp-sourcemaps/map-sources/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "node_modules/@gulp-sourcemaps/map-sources/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } + "safe-buffer": "~5.1.0" } }, - "append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "node_modules/@gulp-sourcemaps/map-sources/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "requires": { - "buffer-equal": "^1.0.0" + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@gulpjs/messages": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", + "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==", "dev": true, - "requires": { - "sprintf-js": "~1.0.2" + "engines": { + "node": ">=10.13.0" } }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "node_modules/@gulpjs/to-absolute-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz", + "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==", "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "dependencies": { + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "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==", + "deprecated": "Use @eslint/config-array instead", "dev": true, - "requires": { - "make-iterator": "^1.0.0" + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" } }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "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, - "requires": { - "make-iterator": "^1.0.0" + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true }, - "array-initial": { + "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "requires": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" - }, "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } + "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" } }, - "array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "node_modules/@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, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true - }, - "array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, - "requires": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" - }, "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "node_modules/@jest/console/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "node_modules/@jest/console/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "async-done": "^1.2.2" + "dependencies": { + "@types/yargs-parser": "*" } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "node_modules/@jest/console/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.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/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, "dependencies": { - "@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "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 + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@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.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.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 } } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/@jest/core/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, - "requires": { - "object.assign": "^4.1.0" + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "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.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.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" } }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "node_modules/@jest/core/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "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": "^4.0.0", - "test-exclude": "^6.0.0" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "node_modules/@jest/core/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "dependencies": { + "@types/yargs-parser": "*" } }, - "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==", + "node_modules/@jest/core/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, - "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" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "node_modules/@jest/core/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" + "dependencies": { + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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" } }, - "bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "node_modules/@jest/core/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "requires": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/@jest/core/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - } + "@jest/types": "^29.6.3", + "@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" } }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "binaryextensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", - "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "node_modules/@jest/core/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, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "body": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, - "requires": { - "continuable-cache": "^0.3.1", - "error": "^7.0.0", - "raw-body": "~1.1.0", - "safe-json-parse": "~1.0.1" + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "bootstrap": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@jest/environment/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "node_modules/@jest/environment/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, "dependencies": { - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "@types/yargs-parser": "*" } }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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/fake-timers/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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/globals/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@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": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "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.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.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/reporters/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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/reporters/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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/reporters/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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/reporters/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/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/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "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.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@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-result/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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/test-result/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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/test-sequencer/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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/test-sequencer/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/transform/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/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "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==", + "dev": true, + "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/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.6.tgz", + "integrity": "sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "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==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.3.1.tgz", + "integrity": "sha512-q/WL+vlXMpC0uXDyfsMtc1rmotzLV8Y0gq6q1gfrrDjQeHoeLrqHbxdPvPNAh1i+xuJl7+BezywcXArz7vLqKQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.6.tgz", + "integrity": "sha512-8qpnGVincVDLEcQXWaHOf6zmlbwTKc6Us6PPu4CRnPXCzo2OGBS5cwgMMOWdxDpEz1mkbvXHpEy99M5Yvt682w==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/bun": "latest", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/bun": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true + }, + "node_modules/@testing-library/react": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", + "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true + }, + "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==", + "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.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/expect": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz", + "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", + "dev": true + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/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/@types/jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "optional": true, + "peer": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "optional": true, + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/redux-mock-store": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/redux-mock-store/-/redux-mock-store-1.0.6.tgz", + "integrity": "sha512-eg5RDfhJTXuoJjOMyXiJbaDb1B8tfTaJixscmu+jOusj6adGC0Krntz09Tf4gJgXeCqCrM5bBMd+B7ez0izcAQ==", + "dev": true, + "dependencies": { + "redux": "^4.0.5" + } + }, + "node_modules/@types/redux-mock-store/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "node_modules/@types/vinyl": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.12.tgz", + "integrity": "sha512-Sr2fYMBUVGYq8kj3UthXFAu5UN6ZW+rYr4NACjZQJvHvj+c8lYv0CahmZ2P/r7iUkN44gGUBwqxZkrKXYPb7cw==", + "dev": true, + "dependencies": { + "@types/expect": "^1.20.4", + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", + "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/type-utils": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "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.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", + "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.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.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", + "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.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.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", + "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "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.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", + "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "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.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", + "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "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/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "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/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "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.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", + "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "eslint-visitor-keys": "^3.4.3" + }, + "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/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "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.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "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==", + "dev": true, + "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-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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": "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/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-done": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/async-settle": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", + "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.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==", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, + "node_modules/babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "dev": true, + "dependencies": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "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": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/bach": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz", + "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "now-and-later": "^3.0.0" + }, + "engines": { + "node": ">=10.13.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/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "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/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binaryextensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", + "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "dev": true, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", + "dev": true, + "dependencies": { + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + } + }, + "node_modules/bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "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.30001629", + "electron-to-chromium": "^1.4.796", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.16" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", + "dev": true + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", + "dev": true, + "dependencies": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001640", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", + "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", + "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/capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "dependencies": { + "rsvp": "^4.8.4" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "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/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/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/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/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", + "dev": true + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/cloneable-readable/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/cloneable-readable/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/cloneable-readable/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/cloneable-readable/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/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/codemirror": { + "version": "5.65.16", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", + "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", + "dev": true + }, + "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/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz", + "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==", + "dev": true, + "dependencies": { + "each-props": "^3.0.0", + "is-plain-object": "^5.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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/create-jest/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/create-jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "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/css": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "source-map": "^0.6.1", + "source-map-resolve": "^0.6.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "optional": true, + "peer": true + }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg==", + "dev": true, + "dependencies": { + "get-stdin": "^4.0.1", + "meow": "^3.3.0" + }, + "bin": { + "dateformat": "bin/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug-fabulous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", + "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", + "dev": true, + "dependencies": { + "debug": "3.X", + "memoizee": "0.4.X", + "object-assign": "4.X" + } + }, + "node_modules/debug-fabulous/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/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==", + "dev": true, + "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-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "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/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" + }, + "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/dir-glob/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/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-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==", + "dev": true, + "dependencies": { + "readable-stream": "~1.1.9" + } + }, + "node_modules/duplexer2/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==", + "dev": true + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/each-props": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz", + "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==", + "dev": true, + "dependencies": { + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.820", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.820.tgz", + "integrity": "sha512-kK/4O/YunacfboFEk/BDf7VO1HoPmDudLTJAU9NmXIOSjsV7qVIX3OrI4REZo0VmdqhcpUcncQc6N8Q3aEXlHg==", + "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==" + }, + "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/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "dev": true, + "dependencies": { + "string-template": "~0.2.1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "dev": true, + "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": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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-jest": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/esbuild-jest/-/esbuild-jest-0.5.0.tgz", + "integrity": "sha512-AMZZCdEpXfNVOIDvURlqYyHwC8qC1/BFjgsrOiSL1eyiIArVtHL8YAC83Shhn16cYYoAWEW17yZn0W/RJKJKHQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.17", + "@babel/plugin-transform-modules-commonjs": "^7.12.13", + "babel-jest": "^26.6.3" + }, + "peerDependencies": { + "esbuild": ">=0.8.50" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "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/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-plugin-react": { + "version": "7.34.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", + "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-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-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/@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/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/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/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/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/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==", + "dev": true, + "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/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/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.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "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/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/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/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true + }, + "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/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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/expect/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/expect/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "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==", + "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/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/fined": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz", + "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "parse-filepath": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/flagged-respawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz", + "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } + }, + "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==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz", + "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.8", + "streamx": "^2.12.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "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==", + "dev": true, + "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-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "dev": true, + "engines": { + "node": ">=0.10.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/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/glob-stream": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.2.tgz", + "integrity": "sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==", + "dev": true, + "dependencies": { + "@gulpjs/to-absolute-glob": "^4.0.0", + "anymatch": "^3.1.3", + "fastq": "^1.13.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "is-negated-glob": "^1.0.0", + "normalize-path": "^3.0.0", + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-watcher": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz", + "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "chokidar": "^3.5.3" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/glogg": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", + "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==", + "dev": true, + "dependencies": { + "sparkles": "^2.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", + "dev": true + }, + "node_modules/gulp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.0.tgz", + "integrity": "sha512-S8Z8066SSileaYw1S2N1I64IUc/myI2bqe2ihOBzO6+nKpvNSg7ZcWJt/AwF8LC/NVN+/QZ560Cb/5OPsyhkhg==", + "dev": true, + "dependencies": { + "glob-watcher": "^6.0.0", + "gulp-cli": "^3.0.0", + "undertaker": "^2.0.0", + "vinyl-fs": "^4.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-clean-css": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.3.0.tgz", + "integrity": "sha512-mGyeT3qqFXTy61j0zOIciS4MkYziF2U594t2Vs9rUnpkEHqfu6aDITMp8xOvZcvdX61Uz3y1mVERRYmjzQF5fg==", + "dev": true, + "dependencies": { + "clean-css": "4.2.3", + "plugin-error": "1.0.1", + "through2": "3.0.1", + "vinyl-sourcemaps-apply": "0.2.1" + } + }, + "node_modules/gulp-clean-css/node_modules/through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "dependencies": { + "readable-stream": "2 || 3" + } + }, + "node_modules/gulp-cli": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.0.0.tgz", + "integrity": "sha512-RtMIitkT8DEMZZygHK2vEuLPqLPAFB4sntSxg4NoDta7ciwGZ18l7JuhCTiS5deOJi2IoK0btE+hs6R4sfj7AA==", + "dev": true, + "dependencies": { + "@gulpjs/messages": "^1.1.0", + "chalk": "^4.1.2", + "copy-props": "^4.0.0", + "gulplog": "^2.2.0", + "interpret": "^3.1.1", + "liftoff": "^5.0.0", + "mute-stdout": "^2.0.0", + "replace-homedir": "^2.0.0", + "semver-greatest-satisfied-range": "^2.0.0", + "string-width": "^4.2.3", + "v8flags": "^4.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-esbuild": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/gulp-esbuild/-/gulp-esbuild-0.12.1.tgz", + "integrity": "sha512-dkcN2AHtXTVu+KNw0Zw8SWysziNwpYg6kw41E8frUkil5ZtwktIsot/OCLEpRT6clFpVQ7Hw3+YZQvoNdyTF1A==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.5", + "plugin-error": "^2.0.1", + "vinyl": "^3.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/gulp-esbuild/node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-esbuild/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/gulp-esbuild/node_modules/plugin-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz", + "integrity": "sha512-zMakqvIDyY40xHOvzXka0kUvf40nYIuwRE8dWhti2WtjQZ31xAgBZBhxsK7vK3QbRXS1Xms/LO7B5cuAsfB2Gg==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-less": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-5.0.0.tgz", + "integrity": "sha512-W2I3TewO/By6UZsM/wJG3pyK5M6J0NYmJAAhwYXQHR+38S0iDtZasmUgFCH3CQj+pQYw/PAIzxvFvwtEXz1HhQ==", + "dev": true, + "dependencies": { + "less": "^3.7.1 || ^4.0.0", + "object-assign": "^4.0.1", + "plugin-error": "^1.0.0", + "replace-ext": "^2.0.0", + "through2": "^4.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-livereload": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp-livereload/-/gulp-livereload-4.0.2.tgz", + "integrity": "sha512-InmaR50Xl1xB1WdEk4mrUgGHv3VhhlRLrx7u60iY5AAer90FlK95KXitPcGGQoi28zrUJM189d/h6+V470Ncgg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "debug": "^3.1.0", + "fancy-log": "^1.3.2", + "lodash.assign": "^4.2.0", + "readable-stream": "^3.0.6", + "tiny-lr": "^1.1.1", + "vinyl": "^2.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-livereload/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/gulp-livereload/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/gulp-livereload/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/gulp-livereload/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/gulp-livereload/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/gulp-livereload/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/gulp-livereload/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/gulp-livereload/node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-livereload/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/gulp-livereload/node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-notify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-4.0.0.tgz", + "integrity": "sha512-0cdDvZkHVqu4tqrcOI/jL5YdxYEIPQ7+p3YxnO48w5hhPSisvogZ887qL+fpYItg9m4MUhJ5Se8p8xGy3uJESA==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "fancy-log": "^1.3.3", + "lodash.template": "^4.5.0", + "node-notifier": "^9.0.1", + "node.extend": "^2.0.2", + "plugin-error": "^1.0.1", + "through2": "^4.0.2" + }, + "engines": { + "node": ">=0.8.0", + "npm": ">=1.2.10" + } + }, + "node_modules/gulp-peg": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/gulp-peg/-/gulp-peg-0.2.0.tgz", + "integrity": "sha512-A8SWTea7/tj/6/mdfHI92C2ATdABLs9arbRi8a/aZLhQ9ZK70S73udo0qv6OjgxWZoQqEjwrPmbJaQzym/yHfg==", + "dev": true, + "dependencies": { + "gulp-util": "^2.2.14", + "pegjs": "^0.9.0", + "through2": "^0.4.1" + } + }, + "node_modules/gulp-peg/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==", + "dev": true + }, + "node_modules/gulp-peg/node_modules/object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==", + "dev": true + }, + "node_modules/gulp-peg/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/gulp-peg/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/gulp-peg/node_modules/through2": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", + "dev": true, + "dependencies": { + "readable-stream": "~1.0.17", + "xtend": "~2.1.1" + } + }, + "node_modules/gulp-peg/node_modules/xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", + "dev": true, + "dependencies": { + "object-keys": "~0.4.0" + }, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/gulp-plumber": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/gulp-plumber/-/gulp-plumber-1.2.1.tgz", + "integrity": "sha512-mctAi9msEAG7XzW5ytDVZ9PxWMzzi1pS2rBH7lA095DhMa6KEXjm+St0GOCc567pJKJ/oCvosVAZEpAey0q2eQ==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "fancy-log": "^1.3.2", + "plugin-error": "^0.1.2", + "through2": "^2.0.3" + }, + "engines": { + "node": ">=0.10", + "npm": ">=1.2.10" + } + }, + "node_modules/gulp-plumber/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/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/gulp-plumber/node_modules/extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", + "dev": true, + "dependencies": { + "kind-of": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/gulp-plumber/node_modules/plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", + "dev": true, + "dependencies": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-plumber/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/gulp-plumber/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-plumber/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-plumber/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/gulp-plumber/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-replace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.1.4.tgz", + "integrity": "sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/vinyl": "^2.0.4", + "istextorbinary": "^3.0.0", + "replacestream": "^4.0.3", + "yargs-parser": ">=5.0.0-security.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gulp-sourcemaps": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", + "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==", + "dev": true, + "dependencies": { + "@gulp-sourcemaps/identity-map": "^2.0.1", + "@gulp-sourcemaps/map-sources": "^1.0.0", + "acorn": "^6.4.1", + "convert-source-map": "^1.0.0", + "css": "^3.0.0", + "debug-fabulous": "^1.0.0", + "detect-newline": "^2.0.0", + "graceful-fs": "^4.0.0", + "source-map": "^0.6.0", + "strip-bom-string": "^1.0.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gulp-sourcemaps/node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/gulp-sourcemaps/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/gulp-sourcemaps/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/gulp-sourcemaps/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-sourcemaps/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/gulp-sourcemaps/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-sourcemaps/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-util": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", + "integrity": "sha512-9rtv4sj9EtCWYGD15HQQvWtRBtU9g1t0+w29tphetHxjxEAuBKQJkhGqvlLkHEtUjEgoqIpsVwPKU1yMZAa+wA==", + "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", + "dev": true, + "dependencies": { + "chalk": "^0.5.0", + "dateformat": "^1.0.7-1.2.3", + "lodash._reinterpolate": "^2.4.1", + "lodash.template": "^2.4.1", + "minimist": "^0.2.0", + "multipipe": "^0.1.0", + "through2": "^0.5.0", + "vinyl": "^0.2.1" + }, + "engines": { + "node": ">= 0.9" + } + }, + "node_modules/gulp-util/node_modules/ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha512-sGwIGMjhYdW26/IhwK2gkWWI8DRCVO6uj3hYgHT+zD+QL1pa37tM3ujhyfcJIYSbsxp7Gxhy7zrRW/1AHm4BmA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha512-f2PKUkN5QngiSemowa6Mrk9MPCdtFiOSmibjZ+j1qhLGHHYsqZwmBMRF3IRMVXo8sybDqx2fJl2d/8OphBoWkA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/chalk": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha512-bIKA54hP8iZhyDT81TOsJiQvR1gW+ZYSXFaZUAvoD4wCHdbHY2actmpTE4x344ZlFqHbvoxKOaESULTZN2gstg==", + "dev": true, + "dependencies": { + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", + "dev": true + }, + "node_modules/gulp-util/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/gulp-util/node_modules/has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha512-1YsTg1fk2/6JToQhtZkArMkurq8UoWU1Qe0aR3VUHjgij4nOylSWLWAtBXoZ4/dXOmugfLGm1c+QhuD0JyedFA==", + "dev": true, + "dependencies": { + "ansi-regex": "^0.2.0" + }, + "bin": { + "has-ansi": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/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==", + "dev": true + }, + "node_modules/gulp-util/node_modules/lodash.template": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz", + "integrity": "sha512-5yLOQwlS69xbaez3g9dA1i0GMAj8pLDHp8lhA4V7M1vRam1lqD76f0jg5EV+65frbqrXo1WH9ZfKalfYBzJ5yQ==", + "dev": true, + "dependencies": { + "lodash._escapestringchar": "~2.4.1", + "lodash._reinterpolate": "~2.4.1", + "lodash.defaults": "~2.4.1", + "lodash.escape": "~2.4.1", + "lodash.keys": "~2.4.1", + "lodash.templatesettings": "~2.4.1", + "lodash.values": "~2.4.1" + } + }, + "node_modules/gulp-util/node_modules/lodash.templatesettings": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz", + "integrity": "sha512-vY3QQ7GxbeLe8XfTvoYDbaMHO5iyTDJS1KIZrxp00PRMmyBKr8yEcObHSl2ppYTwd8MgqPXAarTvLA14hx8ffw==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "~2.4.1", + "lodash.escape": "~2.4.1" + } + }, + "node_modules/gulp-util/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/gulp-util/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/gulp-util/node_modules/strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha512-DerhZL7j6i6/nEnVG0qViKXI0OKouvvpsAiaj7c+LfqZZZxdwZtv8+UiA/w4VUJpT8UzX0pR1dcHOii1GbmruQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^0.2.1" + }, + "bin": { + "strip-ansi": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha512-tdCZ28MnM7k7cJDJc7Eq80A9CsRFAAOZUy41npOZCs++qSjfIy7o5Rh46CBk+Dk5FbKJ33X3Tqg4YrV07N5RaA==", + "dev": true, + "bin": { + "supports-color": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-util/node_modules/through2": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "integrity": "sha512-zexCrAOTbjkBCXGyozn7hhS3aEaqdrc59mAD2E3dKYzV1vFuEGQ1hEDJN2oQMQFwy4he2zyLqPZV+AlfS8ZWJA==", + "dev": true, + "dependencies": { + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" + } + }, + "node_modules/gulp-util/node_modules/vinyl": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz", + "integrity": "sha512-4gFk9xrecazOTuFKcUYrE1TjHSYL63dio72D+q0d1mHF51FEcxTT2RHFpHbN5TNJgmPYHuVsBdhvXEOCDcytSA==", + "dev": true, + "dependencies": { + "clone-stats": "~0.0.1" + }, + "engines": { + "node": ">= 0.9" + } + }, + "node_modules/gulp-util/node_modules/xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha512-sp/sT9OALMjRW1fKDlPeuSZlDQpkqReA0pyJukniWbTGoEKefHxhGJynE3PNhUMlcM8qWIjPwecwCw4LArS5Eg==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/gulplog": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz", + "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==", + "dev": true, + "dependencies": { + "glogg": "^2.2.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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-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==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "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.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.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==", + "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/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "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==", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-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==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "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-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-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-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "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==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "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==", + "dev": true + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "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==", + "dev": true + }, + "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/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "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.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "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.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istextorbinary": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-3.3.0.tgz", + "integrity": "sha512-Tvq1W6NAcZeJ8op+Hq7tdZ434rqnMx4CCZ7H0ff83uEloDvVbqAwaMTZcafKGJT0VHkYzuXUiCY4hlXQg6WfoQ==", + "dev": true, + "dependencies": { + "binaryextensions": "^2.2.0", + "textextensions": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.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.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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-changed-files/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-changed-files/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.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/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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-circus/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-circus/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/jest-circus/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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-circus/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "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/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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-cli/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-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==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-cli/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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-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==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "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/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.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.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.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 + } } }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/jest-config/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, - "requires": { - "node-int64": "^0.4.0" + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "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.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.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" } }, - "buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", - "dev": true + "node_modules/jest-config/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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" + } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "node_modules/jest-config/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "node_modules/jest-config/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" + } }, - "bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", - "dev": true + "node_modules/jest-config/node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "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" + } }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "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" } }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/jest-config/node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "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" } }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "node_modules/jest-config/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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" + } }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true + "node_modules/jest-config/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "node_modules/jest-config/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "dependencies": { + "@jest/types": "^29.6.3", + "@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-config/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - } + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001239", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz", - "integrity": "sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ==", + "node_modules/jest-config/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "node_modules/jest-config/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, - "requires": { - "rsvp": "^4.8.4" + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.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 - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "node_modules/jest-diff/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, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "dependencies": { - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "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": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", - "dev": true + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "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==", + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "dependencies": { + "detect-newline": "^3.0.0" }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock/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/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + "node_modules/jest-each/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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" + } }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "node_modules/jest-each/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "source-map": "~0.6.0" + "dependencies": { + "@types/yargs-parser": "*" } }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/jest-each/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, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "engines": { + "node": ">=10" }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, "dependencies": { - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - } + "@jest/types": "^29.6.3", + "@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" } }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "node_modules/jest-each/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } }, - "cloneable-readable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "node_modules/jest-environment-jsdom/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true + "node_modules/jest-environment-jsdom/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "node_modules/jest-environment-jsdom/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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" + } }, - "codemirror": { - "version": "5.62.3", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", - "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "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/jest-environment-node/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.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" + } }, - "collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "node_modules/jest-environment-node/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "dependencies": { + "@types/yargs-parser": "*" } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "dependencies": { + "@jest/types": "^29.6.3", + "@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" } }, - "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==", + "node_modules/jest-fetch-mock": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", + "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", "dev": true, - "requires": { - "color-name": "1.1.3" + "dependencies": { + "cross-fetch": "^3.0.4", + "promise-polyfill": "^8.1.3" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, - "requires": { - "delayed-stream": "~1.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "node_modules/jest-haste-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "dependencies": { + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "fsevents": "^2.1.2" } }, - "continuable-cache": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "node_modules/jest-haste-map/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "copy-anything": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.3.tgz", - "integrity": "sha512-GK6QUtisv4fNS+XcI7shX0Gx9ORg7QqIznyfho79JTnX1XhLiyZHfftvGiziqzRiEi/Bjhgpi+D2o7HxJFPnDQ==", + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, - "requires": { - "is-what": "^3.12.0" + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-props": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", - "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "node_modules/jest-leak-detector/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, - "requires": { - "each-props": "^1.3.2", - "is-plain-object": "^5.0.0" + "engines": { + "node": ">=10" }, - "dependencies": { - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "core-js-pure": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.2.tgz", - "integrity": "sha512-oxKe64UH049mJqrKkynWp6Vu0Rlm/BTXO/bJZuN2mmR3RtOFNepLlSWDd1eo16PzHpQAoNG97rLU1V/YxesJjw==", - "dev": true + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.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=", + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, - "requires": { - "node-fetch": "2.6.1" + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.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==", + "node_modules/jest-matcher-utils/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, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "engines": { + "node": ">=10" }, - "dependencies": { - "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 - }, - "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" - } - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, - "requires": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - }, "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - } + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", - "dev": true - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, - "requires": { - "cssom": "~0.3.6" - }, "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "csstype": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "array-find-index": "^1.0.1" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "d": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "node_modules/jest-message-util/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "es5-ext": "^0.10.9" + "dependencies": { + "@types/yargs-parser": "*" } }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "node_modules/jest-message-util/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, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, - "requires": { - "ms": "2.1.2" - }, "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "debug-fabulous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "debug": "3.X", - "memoizee": "0.4.X", - "object-assign": "4.X" - }, "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "@jest/schemas": "^29.6.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" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/jest-mock/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true + "node_modules/jest-mock/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@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" + } }, - "default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "node_modules/jest-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": { - "kind-of": "^5.0.2" + "engines": { + "node": ">=6" }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true } } }, - "default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "node_modules/jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", "dev": true, - "requires": { - "object-keys": "^1.0.12" + "engines": { + "node": ">= 10.14.2" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.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" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, - "diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", - "dev": true - }, - "dijkstrajs": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", - "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "dom-accessibility-api": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.7.tgz", - "integrity": "sha512-ml3lJIq9YjUfM9TUnEPvEYWFSwivwIGBPKpewX7tii7fwCazA8yCioGdqQcNsItPpfFvSJ3VIdMQPj60LJhcQA==", - "dev": true + "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/jest-resolve/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" + "dependencies": { + "@jest/schemas": "^29.6.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-resolve/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } + "@types/yargs-parser": "*" } }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "node_modules/jest-resolve/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "requires": { - "readable-stream": "~1.1.9" - }, "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - } + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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" } }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "node_modules/jest-resolve/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" + "dependencies": { + "@jest/types": "^29.6.3", + "@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" } }, - "electron-to-chromium": { - "version": "1.3.752", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz", - "integrity": "sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A==", - "dev": true - }, - "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "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==" - }, - "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==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/jest-resolve/node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, - "requires": { - "once": "^1.4.0" + "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" } }, - "errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, - "optional": true, - "requires": { - "prr": "~1.0.1" + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.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/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "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.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.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" } }, - "error": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "node_modules/jest-runner/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "string-template": "~0.2.1" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "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==", + "node_modules/jest-runner/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "is-arrayish": "^0.2.1" + "dependencies": { + "@types/yargs-parser": "*" } }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "node_modules/jest-runner/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "dependencies": { + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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" } }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "node_modules/jest-runner/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "node_modules/jest-runner/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - }, - "dependencies": { - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - } + "dependencies": { + "@jest/types": "^29.6.3", + "@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" } }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "node_modules/jest-runner/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, - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "esbuild": { - "version": "0.12.21", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.21.tgz", - "integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==", - "dev": true - }, - "esbuild-jest": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/esbuild-jest/-/esbuild-jest-0.5.0.tgz", - "integrity": "sha512-AMZZCdEpXfNVOIDvURlqYyHwC8qC1/BFjgsrOiSL1eyiIArVtHL8YAC83Shhn16cYYoAWEW17yZn0W/RJKJKHQ==", + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, - "requires": { - "@babel/core": "^7.12.17", - "@babel/plugin-transform-modules-commonjs": "^7.12.13", - "babel-jest": "^26.6.3" + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@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.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "node_modules/jest-runtime/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "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.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.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" } }, - "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 - }, - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "node_modules/jest-runtime/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/jest-runtime/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "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" - }, "dependencies": { - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - } + "@types/yargs-parser": "*" } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "node_modules/jest-runtime/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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" } }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "node_modules/jest-runtime/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "expect": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.6.tgz", - "integrity": "sha512-psNLt8j2kwg42jGBDSfAlU49CEZxejN1f1PlANWDZqIhBOVU/c2Pm888FcjWJzFewhIsNWfZJeLjUjtKGiPuSw==", + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-regex-util": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - } + "dependencies": { + "@jest/types": "^29.6.3", + "@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" } }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "node_modules/jest-runtime/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, - "requires": { - "type": "^2.0.0" - }, "dependencies": { - "type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", - "dev": true - } + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "node_modules/jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "@types/node": "*", + "graceful-fs": "^4.2.4" + }, + "engines": { + "node": ">= 10.14.2" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "@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/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "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.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.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" } }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "node_modules/jest-snapshot/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "node_modules/jest-snapshot/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "bser": "^2.0.0" + "dependencies": { + "@types/yargs-parser": "*" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "node_modules/jest-snapshot/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, - "optional": true + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "node_modules/jest-snapshot/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "@jest/types": "^29.6.3", + "@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.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.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" } }, - "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" + "node_modules/jest-snapshot/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } + "@jest/types": "^29.6.3", + "@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" } }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "node_modules/jest-snapshot/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, - "requires": { - "for-in": "^1.0.1" + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/jest-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", "dev": true, - "requires": { - "map-cache": "^0.2.2" + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">= 10.14.2" } }, - "fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" - }, "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/jest-validate/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.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==" + "dependencies": { + "@jest/schemas": "^29.6.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" + } }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "node_modules/jest-validate/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "dependencies": { + "@types/yargs-parser": "*" } }, - "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 + "node_modules/jest-validate/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" + } }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true + "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" + } }, - "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 + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "node_modules/jest-watcher/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "glob-watcher": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "node_modules/jest-watcher/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "object.defaults": "^1.1.0" + "dependencies": { + "@types/yargs-parser": "*" } }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "dependencies": { + "@jest/types": "^29.6.3", + "@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" } }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "node_modules/jest-worker/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "sparkles": "^1.0.0" + "dependencies": { + "@jest/schemas": "^29.6.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" } }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "node_modules/jest-worker/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" - }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "gulp-cli": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz", - "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==", - "dev": true, - "requires": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.1.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.0.1", - "yargs": "^7.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - } - }, - "y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true - }, - "yargs": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", - "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.1" - } - }, - "yargs-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", - "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "object.assign": "^4.1.0" - } - } + "@types/yargs-parser": "*" } }, - "gulp-clean-css": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.3.0.tgz", - "integrity": "sha512-mGyeT3qqFXTy61j0zOIciS4MkYziF2U594t2Vs9rUnpkEHqfu6aDITMp8xOvZcvdX61Uz3y1mVERRYmjzQF5fg==", + "node_modules/jest-worker/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { - "clean-css": "4.2.3", - "plugin-error": "1.0.1", - "through2": "3.0.1", - "vinyl-sourcemaps-apply": "0.2.1" + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, - "dependencies": { - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "dev": true, - "requires": { - "readable-stream": "2 || 3" - } - } + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "gulp-esbuild": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/gulp-esbuild/-/gulp-esbuild-0.8.5.tgz", - "integrity": "sha512-t69FaHlVjxcV2NMZAvqlKqGwecrDuTWizMhkmoPfVLlCT1lMa4x7Oz99dIBjeRrzEQ8Y+uPk0kDb7AwWZ5bWAw==", + "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, - "requires": { - "esbuild": "^0.12.18", - "plugin-error": "^1.0.1", - "vinyl": "^2.2.1" - }, - "dependencies": { - "vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "gulp-less": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-5.0.0.tgz", - "integrity": "sha512-W2I3TewO/By6UZsM/wJG3pyK5M6J0NYmJAAhwYXQHR+38S0iDtZasmUgFCH3CQj+pQYw/PAIzxvFvwtEXz1HhQ==", + "node_modules/jest/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { - "less": "^3.7.1 || ^4.0.0", - "object-assign": "^4.0.1", - "plugin-error": "^1.0.0", - "replace-ext": "^2.0.0", - "through2": "^4.0.0", - "vinyl-sourcemaps-apply": "^0.2.0" - }, "dependencies": { - "replace-ext": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", - "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", - "dev": true - } + "@jest/schemas": "^29.6.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" } }, - "gulp-livereload": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp-livereload/-/gulp-livereload-4.0.2.tgz", - "integrity": "sha512-InmaR50Xl1xB1WdEk4mrUgGHv3VhhlRLrx7u60iY5AAer90FlK95KXitPcGGQoi28zrUJM189d/h6+V470Ncgg==", + "node_modules/jest/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "requires": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "fancy-log": "^1.3.2", - "lodash.assign": "^4.2.0", - "readable-stream": "^3.0.6", - "tiny-lr": "^1.1.1", - "vinyl": "^2.2.0" - }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@types/yargs-parser": "*" } }, - "gulp-notify": { + "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-4.0.0.tgz", - "integrity": "sha512-0cdDvZkHVqu4tqrcOI/jL5YdxYEIPQ7+p3YxnO48w5hhPSisvogZ887qL+fpYItg9m4MUhJ5Se8p8xGy3uJESA==", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "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, - "requires": { - "ansi-colors": "^4.1.1", - "fancy-log": "^1.3.3", - "lodash.template": "^4.5.0", - "node-notifier": "^9.0.1", - "node.extend": "^2.0.2", - "plugin-error": "^1.0.1", - "through2": "^4.0.2" - }, "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - } + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "gulp-peg": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/gulp-peg/-/gulp-peg-0.2.0.tgz", - "integrity": "sha1-aap3iezv+ajBA94ghYt8t4jXlSY=", + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, - "requires": { - "gulp-util": "^2.2.14", - "pegjs": "^0.9.0", - "through2": "^0.4.1" - }, "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", - "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - } - }, - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true } } }, - "gulp-plumber": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/gulp-plumber/-/gulp-plumber-1.2.1.tgz", - "integrity": "sha512-mctAi9msEAG7XzW5ytDVZ9PxWMzzi1pS2rBH7lA095DhMa6KEXjm+St0GOCc567pJKJ/oCvosVAZEpAey0q2eQ==", + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, - "requires": { - "chalk": "^1.1.3", - "fancy-log": "^1.3.2", - "plugin-error": "^0.1.2", - "through2": "^2.0.3" + "bin": { + "jsesc": "bin/jsesc" }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - } - }, - "arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", - "dev": true - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "dependencies": { - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "dev": true, - "requires": { - "kind-of": "^1.1.0" - } - }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", - "dev": true - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "dev": true, - "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - }, - "dependencies": { - "ansi-cyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", - "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-red": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - } + "engines": { + "node": ">=4" } }, - "gulp-replace": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.1.3.tgz", - "integrity": "sha512-HcPHpWY4XdF8zxYkDODHnG2+7a3nD/Y8Mfu3aBgMiCFDW3X2GiOKXllsAmILcxe3KZT2BXoN18WrpEFm48KfLQ==", + "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==", + "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, - "requires": { - "@types/node": "^14.14.41", - "@types/vinyl": "^2.0.4", - "istextorbinary": "^3.0.0", - "replacestream": "^4.0.3", - "yargs-parser": ">=5.0.0-security.0" + "bin": { + "json5": "lib/cli.js" }, - "dependencies": { - "@types/node": { - "version": "14.17.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz", - "integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw==", - "dev": true - } + "engines": { + "node": ">=6" } }, - "gulp-sourcemaps": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", - "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==", + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, - "requires": { - "@gulp-sourcemaps/identity-map": "^2.0.1", - "@gulp-sourcemaps/map-sources": "^1.0.0", - "acorn": "^6.4.1", - "convert-source-map": "^1.0.0", - "css": "^3.0.0", - "debug-fabulous": "^1.0.0", - "detect-newline": "^2.0.0", - "graceful-fs": "^4.0.0", - "source-map": "^0.6.0", - "strip-bom-string": "^1.0.0", - "through2": "^2.0.0" - }, "dependencies": { - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - } + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" } }, - "gulp-util": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", - "integrity": "sha1-1xRuVyiRC9jwR6awseVJvCLb1kw=", + "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, - "requires": { - "chalk": "^0.5.0", - "dateformat": "^1.0.7-1.2.3", - "lodash._reinterpolate": "^2.4.1", - "lodash.template": "^2.4.1", - "minimist": "^0.2.0", - "multipipe": "^0.1.0", - "through2": "^0.5.0", - "vinyl": "^0.2.1" - }, "dependencies": { - "ansi-regex": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", - "dev": true - }, - "ansi-styles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", - "dev": true - }, - "chalk": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", - "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", - "dev": true, - "requires": { - "ansi-styles": "^1.1.0", - "escape-string-regexp": "^1.0.0", - "has-ansi": "^0.1.0", - "strip-ansi": "^0.3.0", - "supports-color": "^0.2.0" - } - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", - "dev": true, - "requires": { - "ansi-regex": "^0.2.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "lodash.defaults": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.4.1.tgz", - "integrity": "sha1-p+iIXwXmiFEUS24SqPNngCa8TFQ=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, - "lodash.template": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz", - "integrity": "sha1-nmEQB+32KRKal0qzxIuBez4c8g0=", - "dev": true, - "requires": { - "lodash._escapestringchar": "~2.4.1", - "lodash._reinterpolate": "~2.4.1", - "lodash.defaults": "~2.4.1", - "lodash.escape": "~2.4.1", - "lodash.keys": "~2.4.1", - "lodash.templatesettings": "~2.4.1", - "lodash.values": "~2.4.1" - } - }, - "lodash.templatesettings": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz", - "integrity": "sha1-6nbHXRHrhtTb6JqDiTu4YZKaxpk=", - "dev": true, - "requires": { - "lodash._reinterpolate": "~2.4.1", - "lodash.escape": "~2.4.1" - } - }, - "minimist": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.1.tgz", - "integrity": "sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg==", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "strip-ansi": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", - "dev": true, - "requires": { - "ansi-regex": "^0.2.1" - } - }, - "supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", - "dev": true - }, - "through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" - } - }, - "vinyl": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz", - "integrity": "sha1-vKk4IJWC7FpJrVOKAPofEl5RMlI=", - "dev": true, - "requires": { - "clone-stats": "~0.0.1" - } - }, - "xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", - "dev": true - } + "json-buffer": "3.0.1" } }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "node_modules/kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", "dev": true, - "requires": { - "glogg": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "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, - "requires": { - "function-bind": "^1.1.1" + "engines": { + "node": ">=6" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true + "node_modules/last-run": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", + "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "node_modules/lead": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", + "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==", "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "engines": { + "node": ">=10.13.0" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "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" } }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "requires": { - "react-is": "^16.7.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==", + "dev": true, + "optional": true, "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" } }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "node_modules/less/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, - "requires": { - "parse-passwd": "^1.0.0" + "optional": true, + "engines": { + "node": ">=6" } }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "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, - "requires": { - "whatwg-encoding": "^1.0.5" + "engines": { + "node": ">=6" } }, - "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/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" + } }, - "http-parser-js": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", - "dev": true + "node_modules/liftoff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.0.tgz", + "integrity": "sha512-a5BQjbCHnB+cy+gsro8lXJ4kZluzOijzJ1UVVfyJYZC+IP2pLv1h4+aysQeKuTmyO8NAqfyQAk4HWaP/HjcKTg==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "is-plain-object": "^5.0.0", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" + }, + "engines": { + "node": ">=10.13.0" + } }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/liftoff/node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "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" } }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } + "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 }, - "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==", + "node_modules/livereload-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", + "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", "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==", + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", "dev": true, - "optional": true + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.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" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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._escapehtmlchar": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz", + "integrity": "sha512-eHm2t2Lg476lq5v4FVmm3B5mCaRlDyTE8fnMfPCEq2o46G4au0qNXIKh7YWhjprm1zgSMLcMSs1XHMgkw02PbQ==", "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" + "dependencies": { + "lodash._htmlescapes": "~2.4.1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "node_modules/lodash._escapestringchar": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz", + "integrity": "sha512-iZ6Os4iipaE43pr9SBks+UpZgAjJgRC+lGf7onEoByMr1+Nagr1fmR7zCM6Q4RGMB/V3a57raEN0XZl7Uub3/g==", "dev": true }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "node_modules/lodash._htmlescapes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", + "integrity": "sha512-g79hNmMOBVyV+4oKIHM7MWy9Awtk3yqf0Twlawr6f+CmG44nTwBh9I5XiLUnk39KTfYoDBpS66glQGgQCnFIuA==", "dev": true }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "node_modules/lodash._isnative": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", + "integrity": "sha512-BOlKGKNHhCHswGOWtmVb5zBygyxN7EmTuzVOSQI6QSoGhG+kvv71gICFS1TBpnqvT1n53txK8CDK3u5D2/GZxQ==", "dev": true }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "node_modules/lodash._objecttypes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", + "integrity": "sha512-XpqGh1e7hhkOzftBfWE7zt+Yn9mVHFkDhicVttvKLsoCMLVVL+xTQjfjB4X4vtznauxv0QZ5ZAeqjvat0dh62Q==", "dev": true }, - "is": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", + "node_modules/lodash._reinterpolate": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz", + "integrity": "sha512-QGEOOjJi7W9LIgDAMVgtGBb8Qgo8ieDlSOCoZjtG45ZNRvDJZjwVMTYlfTIWdNRUiR1I9BjIqQ3Zaf1+DYM94g==", "dev": true }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "node_modules/lodash._reunescapedhtml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", + "integrity": "sha512-CfmZRU1Mk4E/5jh+Wu8lc7tuc3VkuwWZYVIgdPDH9NRSHgiL4Or3AA4JCIpgrkVzHOM+jKu2OMkAVquruhRHDQ==", "dev": true, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + "dependencies": { + "lodash._htmlescapes": "~2.4.1", + "lodash.keys": "~2.4.1" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/lodash._shimkeys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", + "integrity": "sha512-lBrglYxLD/6KAJ8IEa5Lg+YHgNAL7FyKqXg4XOUI+Du/vtniLs1ZqS+yHNKPkK54waAgkdUnDOYaWf+rv4B+AA==", "dev": true, - "requires": { - "kind-of": "^6.0.0" - }, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } + "lodash._objecttypes": "~2.4.1" } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", "dev": true }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "node_modules/lodash.defaults": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.4.1.tgz", + "integrity": "sha512-5wTIPWwGGr07JFysAZB8+7JB2NjJKXDIwogSaRX5zED85zyUAQwtOqUk8AsJkkigUcL3akbHYXd5+BPtTGQPZw==", "dev": true, - "requires": { - "binary-extensions": "^1.0.0" + "dependencies": { + "lodash._objecttypes": "~2.4.1", + "lodash.keys": "~2.4.1" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "node_modules/lodash.escape": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz", + "integrity": "sha512-PiEStyvZ8gz37qBE+HqME1Yc/ewb/59AMOu8pG7Ztani86foPTxgzckQvMdphmXPY6V5f20Ex/CaNBqHG4/ycQ==", "dev": true, - "requires": { - "builtin-modules": "^1.0.0" + "dependencies": { + "lodash._escapehtmlchar": "~2.4.1", + "lodash._reunescapedhtml": "~2.4.1", + "lodash.keys": "~2.4.1" } }, - "is-ci": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", - "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "node_modules/lodash.isobject": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", + "integrity": "sha512-sTebg2a1PoicYEZXD5PBdQcTlIJ6hUslrlWr7iV0O7n+i4596s2NQ9I5CaZ5FbXSfya/9WQsrYLANUJv9paYVA==", "dev": true, - "requires": { - "ci-info": "^3.1.1" + "dependencies": { + "lodash._objecttypes": "~2.4.1" } }, - "is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/lodash.keys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", + "integrity": "sha512-ZpJhwvUXHSNL5wYd1RM6CUa2ZuqorG9ngoJ9Ix5Cce+uX7I5O/E06FCJdhSZ33b5dVyeQDnIlWH7B2s5uByZ7g==", "dev": true, - "requires": { - "kind-of": "^6.0.0" - }, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } + "lodash._isnative": "~2.4.1", + "lodash._shimkeys": "~2.4.1", + "lodash.isobject": "~2.4.1" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/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.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.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==", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "dev": true - }, - "is-fullwidth-code-point": { + "node_modules/lodash.template/node_modules/lodash._reinterpolate": { "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-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==", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dev": true, - "requires": { - "is-extglob": "^2.1.1" + "dependencies": { + "lodash._reinterpolate": "^3.0.0" } }, - "is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "node_modules/lodash.templatesettings/node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", "dev": true }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "node_modules/lodash.values": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz", + "integrity": "sha512-fQwubKvj2Nox2gy6YnjFm8C1I6MIlzKUtBB+Pj7JGtloGqDDL5CPRr4DUUFWPwXWwAl2k3f4C3Aw8H1qAPB9ww==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "dependencies": { + "lodash.keys": "~2.4.1" } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "node_modules/loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", "dev": true, - "requires": { - "is-unc-path": "^1.0.0" + "dependencies": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + }, + "engines": { + "node": ">=0.10.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==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "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, - "requires": { - "unc-path-regex": "^0.1.2" + "dependencies": { + "yallist": "^3.0.2" } }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", - "dev": true - }, - "is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, - "requires": { - "is-docker": "^2.0.0" + "bin": { + "lz-string": "bin/bin.js" } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "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" + } }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "engines": { + "node": ">=0.10.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==", + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "node_modules/memoizee": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", + "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "dependencies": { + "d": "^1.0.2", + "es5-ext": "^0.10.64", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.12" } }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "node_modules/meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "dependencies": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "istextorbinary": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-3.3.0.tgz", - "integrity": "sha512-Tvq1W6NAcZeJ8op+Hq7tdZ434rqnMx4CCZ7H0ff83uEloDvVbqAwaMTZcafKGJT0VHkYzuXUiCY4hlXQg6WfoQ==", + "node_modules/meow/node_modules/indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", "dev": true, - "requires": { - "binaryextensions": "^2.2.0", - "textextensions": "^3.2.0" + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", - "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", + "node_modules/meow/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "requires": { - "@jest/core": "^27.0.6", - "import-local": "^3.0.2", - "jest-cli": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "jest-cli": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.6.tgz", - "integrity": "sha512-qUUVlGb9fdKir3RDE+B10ULI+LQrz+MCflEH2UJyoUjoHHCbxDrMxSzjQAPUMsic4SncI62ofYCcAvW6+6rhhg==", - "dev": true, - "requires": { - "@jest/core": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "prompts": "^2.0.1", - "yargs": "^16.0.3" - } - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-changed-files": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.6.tgz", - "integrity": "sha512-BuL/ZDauaq5dumYh5y20sn4IISnf1P9A0TDswTxUi84ORGtVa86ApuBHqICL0vepqAnZiY6a7xeSPWv2/yy4eA==", + "node_modules/meow/node_modules/redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "dependencies": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "jest-circus": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.6.tgz", - "integrity": "sha512-OJlsz6BBeX9qR+7O9lXefWoc2m9ZqcZ5Ohlzz0pTEAG4xMiZUJoacY8f4YDHxgk0oKYxj277AfOk9w6hZYvi1Q==", + "node_modules/meow/node_modules/strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", "dev": true, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.0.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "dependencies": { + "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" + }, + "engines": { + "node": ">=0.10.0" } }, - "jest-config": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.6.tgz", - "integrity": "sha512-JZRR3I1Plr2YxPBhgqRspDE2S5zprbga3swYNrvY3HfQGu7p/GjyLOqwrYad97tX3U3mzT53TPHVmozacfP/3w==", + "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, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.0.6", - "@jest/types": "^27.0.6", - "babel-jest": "^27.0.6", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "is-ci": "^3.0.0", - "jest-circus": "^27.0.6", - "jest-environment-jsdom": "^27.0.6", - "jest-environment-node": "^27.0.6", - "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-runner": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "micromatch": "^4.0.4", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "babel-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.6.tgz", - "integrity": "sha512-iTJyYLNc4wRofASmofpOc5NK9QunwMk+TLFgGXsTFS8uEqmd8wdI7sga0FPe2oVH3b5Agt/EAK1QjPEuKL8VfA==", - "dev": true, - "requires": { - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.0.6", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz", - "integrity": "sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz", - "integrity": "sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^27.0.6", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "engines": { + "node": ">= 8" } }, - "jest-diff": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", - "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "jest-docblock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", - "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "requires": { - "detect-newline": "^3.0.0" + "optional": true, + "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==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "dependencies": { - "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 - } + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, - "jest-each": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.6.tgz", - "integrity": "sha512-m6yKcV3bkSWrUIjxkE9OC0mhBZZdhovIW5ergBYirqnkLXkyEn3oUUF/QZgyecA1cF1QFyTE8bRRl8Tfg1pfLA==", + "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, - "requires": { - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "jest-get-type": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "engines": { + "node": ">=6" } }, - "jest-environment-jsdom": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.6.tgz", - "integrity": "sha512-FvetXg7lnXL9+78H+xUAsra3IeZRTiegA3An01cWeXBspKXUhAwMM9ycIJ4yBaR0L7HkoMPaZsozCLHh4T8fuw==", + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6", - "jsdom": "^16.6.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "engines": { + "node": ">=4" } }, - "jest-environment-node": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.6.tgz", - "integrity": "sha512-+Vi6yLrPg/qC81jfXx3IBlVnDTI6kmRr08iVa2hFCWmJt4zha0XW7ucQltCAPhSR0FEKEoJ3i+W4E6T0s9is0w==", + "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, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "jest-fetch-mock": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", - "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "node_modules/minimist": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.4.tgz", + "integrity": "sha512-Pkrrm8NjyQ8yVt8Am9M+yUt74zE3iokhzbG1bFVNjLB92vwM71hf40RkEsryg98BujhVOncKm/C1xROxZ030LQ==", "dev": true, - "requires": { - "cross-fetch": "^3.0.4", - "promise-polyfill": "^8.1.3" + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "jest-haste-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.6.tgz", - "integrity": "sha512-4ldjPXX9h8doB2JlRzg9oAZ2p6/GpQUNAeiYXqcpmrKbP0Qev0wdZlxSMOmz8mPOEnt4h6qIzXFLDi8RScX/1w==", + "node_modules/multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.0.6", - "jest-serializer": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.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==", - "dev": true - } + "duplexer2": "0.0.2" } }, - "jest-jasmine2": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.6.tgz", - "integrity": "sha512-cjpH2sBy+t6dvCeKBsHpW41mjHzXgsavaFMp+VWRf0eR4EW8xASk1acqmljFtK2DgyIECMv2yCdY41r2l1+4iA==", + "node_modules/mute-stdout": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz", + "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==", "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.0.6", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.0.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "engines": { + "node": ">= 10.13.0" } }, - "jest-leak-detector": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.6.tgz", - "integrity": "sha512-2/d6n2wlH5zEcdctX4zdbgX8oM61tb67PQt4Xh8JFAIy6LRKUnX528HulkaG6nD5qDl5vRV1NXejCe1XRCH5gQ==", - "dev": true, - "requires": { - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "jest-matcher-utils": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.6.tgz", - "integrity": "sha512-OFgF2VCQx9vdPSYTHWJ9MzFCehs20TsyFi6bIHbk5V1u52zJOnvF0Y/65z3GLZHKRuTgVPY4Z6LVePNahaQ+tA==", + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", - "dev": true - }, - "jest-diff": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", - "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - } - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "engines": { + "node": ">=0.10.0" } }, - "jest-message-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.6.tgz", - "integrity": "sha512-rBxIs2XK7rGy+zGxgi+UJKP6WqQ+KrBbD1YMj517HYN3v2BG66t3Xan3FWqYHKZwjdB700KiAJ+iES9a0M+ixw==", + "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.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.0.6", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.0.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, + "optional": true, "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" } }, - "jest-mock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.6.tgz", - "integrity": "sha512-lzBETUoK8cSxts2NYXSBWT+EJNzmUVtVVwS1sU9GwE1DLCfGsngg+ZVSIe0yd0ZSm+y791esiuo+WSwpXJQ5Bw==", + "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==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@types/node": "*" - }, "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true } } }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, - "jest-regex-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", - "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, - "jest-resolve": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.6.tgz", - "integrity": "sha512-yKmIgw2LgTh7uAJtzv8UFHGF7Dm7XfvOe/LQ3Txv101fLM8cx2h1QVwtSJ51Q/SCxpIiKfVn6G2jYYMDNHZteA==", + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "escalade": "^3.1.1", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "resolve": "^1.20.0", - "slash": "^3.0.0" - }, "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - } + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, - "jest-resolve-dependencies": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.6.tgz", - "integrity": "sha512-mg9x9DS3BPAREWKCAoyg3QucCr0n6S8HEEsqRCKSPjPcu9HzRILzhdzY3imsLoZWeosEbJZz6TKasveczzpJZA==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } - } + "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 }, - "jest-runner": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.6.tgz", - "integrity": "sha512-W3Bz5qAgaSChuivLn+nKOgjqNxM7O/9JOJoKDCqThPIg2sH/d4A/lzyiaFgnb9V1/w29Le11NpzTJSzga1vyYQ==", + "node_modules/node-notifier": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-9.0.1.tgz", + "integrity": "sha512-fPNFIp2hF/Dq7qLDzSg4vZ0J4e9v60gJR+Qx7RbjbWqzPDdEqeVpEx5CFeDAELIl+A/woaaNn1fQ5nEVerMxJg==", "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/environment": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.0.6", - "jest-environment-node": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-leak-detector": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } - } - }, - "jest-runtime": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.6.tgz", - "integrity": "sha512-BhvHLRVfKibYyqqEFkybsznKwhrsu7AWx2F3y9G9L95VSIN3/ZZ9vBpm/XCS2bS+BWz3sSeNGLzI3TVQ0uL85Q==", - "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/globals": "^27.0.6", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-mock": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.0.3" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" } }, - "jest-serializer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", - "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "node_modules/node-notifier/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "jest-snapshot": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.6.tgz", - "integrity": "sha512-NTHaz8He+ATUagUgE7C/UtFcRoHqR2Gc+KDfhQIyx+VFgwbeEMjeP+ILpUTLosZn/ZtbNdCF5LkVnN/l+V751A==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.0.6", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.0.6", - "jest-get-type": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-util": "^27.0.6", - "natural-compare": "^1.4.0", - "pretty-format": "^27.0.6", - "semver": "^7.3.2" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", - "dev": true - }, - "jest-diff": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", - "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - } - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.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==", + "dev": true }, - "jest-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", - "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "node_modules/node.extend": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.3.tgz", + "integrity": "sha512-xwADg/okH48PvBmRZyoX8i8GJaKuJ1CqlqotlZOhUio8egD1P5trJupHKBzcPjSF9ifK2gPcEICRBnkfPqQXZw==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^3.0.0", - "picomatch": "^2.2.3" - }, "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "hasown": "^2.0.0", + "is": "^3.3.0" + }, + "engines": { + "node": ">=0.4.0" } }, - "jest-validate": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.6.tgz", - "integrity": "sha512-yhZZOaMH3Zg6DC83n60pLmdU1DQE46DW+KLozPiPbSbPhlXXaiUTDlhHQhHFpaqIFRrInko1FHXjTRpjWRuWfA==", + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.0.6", - "leven": "^3.1.0", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "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 - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - } + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "jest-watcher": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.6.tgz", - "integrity": "sha512-/jIoKBhAP00/iMGnTwUBLgvxkn7vsOweDrOTSPzc7X9uOyUtJIDthQBTI1EXz90bdkrxorUZVhJwiB69gcHtYQ==", + "node_modules/normalize-package-data/node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, - "requires": { - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.0.6", - "string-length": "^4.0.1" - }, "dependencies": { - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - } + "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" } }, - "jest-worker": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz", - "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==", + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "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" - } - } + "bin": { + "semver": "bin/semver" } }, - "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/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" + } }, - "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==", + "node_modules/now-and-later": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", + "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==", "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "dependencies": { + "once": "^1.4.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "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, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", - "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", - "dev": true - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - } + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "node_modules/nwsapi": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz", + "integrity": "sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==", "dev": true }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, - "requires": { - "minimist": "^1.2.5" + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "just-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", - "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", - "dev": true + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } }, - "kind-of": { + "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, - "requires": { + "dependencies": { "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "last-run": { + "node_modules/object-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, - "requires": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" + "engines": { + "node": ">= 0.4" } }, - "lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, - "requires": { - "readable-stream": "^2.0.5" + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, - "requires": { - "invert-kv": "^1.0.0" + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, - "requires": { - "flush-write-stream": "^1.0.2" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "less": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.1.tgz", - "integrity": "sha512-w09o8tZFPThBscl5d0Ggp3RcrKIouBoQscnOMgFH3n5V3kN/CXGHNfCkRPtxJk6nKryDXaV9aHLK55RXuH4sAw==", + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, - "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": "^2.5.2", - "parse-node-version": "^1.0.1", - "source-map": "~0.6.0", - "tslib": "^1.10.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==", - "dev": true, - "optional": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "optional": true - } + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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 + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, - "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "livereload-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", - "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", - "dev": true + "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" + } }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "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, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "dependencies": { + "mimic-fn": "^2.1.0" }, - "dependencies": { - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - } + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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" + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash._escapehtmlchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz", - "integrity": "sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=", + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true, - "requires": { - "lodash._htmlescapes": "~2.4.1" + "engines": { + "node": ">=4" } }, - "lodash._escapestringchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz", - "integrity": "sha1-7P4iYYoq3lC/7qQ5N+Ud9m8O23I=", - "dev": true - }, - "lodash._htmlescapes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", - "integrity": "sha1-MtFL8IRLbeb4tioFG09nwii2JMs=", - "dev": true - }, - "lodash._isnative": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", - "integrity": "sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=", - "dev": true - }, - "lodash._objecttypes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", - "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz", - "integrity": "sha1-TxInqlqHEfxjL1sHofRgequLMiI=", - "dev": true - }, - "lodash._reunescapedhtml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", - "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", + "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, - "requires": { - "lodash._htmlescapes": "~2.4.1", - "lodash.keys": "~2.4.1" + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lodash._shimkeys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", - "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1" + "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" } }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true + "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" + } }, - "lodash.escape": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz", - "integrity": "sha1-LOEsXghNsKV92l5dHu659dF1o7Q=", - "dev": true, - "requires": { - "lodash._escapehtmlchar": "~2.4.1", - "lodash._reunescapedhtml": "~2.4.1", - "lodash.keys": "~2.4.1" + "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" } }, - "lodash.isobject": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", - "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", + "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, - "requires": { - "lodash._objecttypes": "~2.4.1" + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, - "lodash.keys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", - "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash._shimkeys": "~2.4.1", - "lodash.isobject": "~2.4.1" + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" } }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "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, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - }, "dependencies": { - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - } + "@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" } }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0" - }, - "dependencies": { - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - } + "engines": { + "node": ">= 0.10" } }, - "lodash.values": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz", - "integrity": "sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=", + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true, - "requires": { - "lodash.keys": "~2.4.1" + "engines": { + "node": ">=0.10.0" } }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "^3.0.0" - }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, "dependencies": { - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - } + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "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==", + "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "requires": { - "yallist": "^4.0.0" + "engines": { + "node": ">=0.10.0" } }, - "lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "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, - "requires": { - "es5-ext": "~0.10.2" + "engines": { + "node": ">=8" } }, - "lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "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 }, - "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==", + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, - "requires": { - "semver": "^6.0.0" + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, - "requires": { - "tmpl": "1.0.x" + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true + "node_modules/pegjs": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.9.0.tgz", + "integrity": "sha512-r8rulH2EvfG7vWrR7nSVRyqsDXWnq3xwW3hCMVEg3xRL0AfjpqfegkHK/WR258qC1wK/dQBn3NIu2RGetaERZg==", + "dev": true, + "bin": { + "pegjs": "bin/pegjs" + }, + "engines": { + "node": ">= 0.10.0" + } }, - "map-obj": { + "node_modules/picocolors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "requires": { - "object-visit": "^1.0.0" + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", - "dev": true, - "requires": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "dependencies": { - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, "dependencies": { - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true - } + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "engines": { + "node": ">= 6" } }, - "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/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" + } }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/plugin-error/node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, "dependencies": { - "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" - } - }, - "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" - } - }, - "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 - }, - "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" - } - } + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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" } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true, - "optional": true + "engines": { + "node": ">=0.10.0" + } }, - "mime-db": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.26.0.tgz", - "integrity": "sha1-6v/NDk/Gk1z4E02iRuLmw1MFrf8=", - "dev": true + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } }, - "mime-types": { - "version": "2.1.14", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.14.tgz", - "integrity": "sha1-9+99l1g/yvO30oK2+LVnnaselO4=", + "node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, - "requires": { - "mime-db": "~1.26.0" + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/postcss/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true + "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" + } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, - "requires": { - "brace-expansion": "^1.1.7" + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "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, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "engines": { + "node": ">=10" }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "node_modules/promise-polyfill": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz", + "integrity": "sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==", + "dev": true + }, + "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, - "requires": { - "duplexer2": "0.0.2" + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" } }, - "mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", - "dev": true + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } }, - "nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, "optional": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } }, - "needle": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.8.0.tgz", - "integrity": "sha512-ZTq6WYkN/3782H1393me3utVYdq2XyqNUFBsprEE3VMAT0+hP/cItpnITpqsY6ep2yeFE4Tqtqwc74VqUlUYtw==", + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "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==", - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "optional": true + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" } + ] + }, + "node_modules/qrcode": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", + "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", + "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" } }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true + "node_modules/qrcode/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" + } }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "node_modules/qrcode/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-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true + "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-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true + "node_modules/qrcode/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-notifier": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-9.0.1.tgz", - "integrity": "sha512-fPNFIp2hF/Dq7qLDzSg4vZ0J4e9v60gJR+Qx7RbjbWqzPDdEqeVpEx5CFeDAELIl+A/woaaNn1fQ5nEVerMxJg==", + "node_modules/qs": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", + "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", "dev": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - }, "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "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" - } - } + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, - "node.extend": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz", - "integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==", + "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, - "requires": { - "has": "^1.0.3", - "is": "^3.2.1" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "normalize-package-data": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", - "integrity": "sha1-jZJPFClg4Xd+f/4XBUNjHMfLAt8=", + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "bytes": "1", + "string_decoder": "0.10" + }, + "engines": { + "node": ">= 0.8.0" } }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } + "node_modules/raw-body/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true }, - "now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", - "dev": true, - "requires": { - "once": "^1.3.2" + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.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==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { - "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 - } + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } + "redux": { + "optional": true } } }, - "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", "dev": true, - "requires": { - "isobject": "^3.0.0" + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, - "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==", + "node_modules/react-test-renderer": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" + "dependencies": { + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" } }, - "object.defaults": { + "node_modules/react-test-renderer/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/read-pkg": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "dev": true, - "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "object.map": { + "node_modules/read-pkg-up": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, - "requires": { - "isobject": "^3.0.1" + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "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==", "dev": true, - "requires": { - "wrappy": "1" + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "requires": { - "mimic-fn": "^2.1.0" + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "node_modules/rechoir/node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, - "requires": { - "readable-stream": "^2.0.1" + "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" } }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, - "requires": { - "lcid": "^1.0.0" + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "node_modules/redux-mock-store": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz", + "integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==", + "dev": true, + "dependencies": { + "lodash.isplainobject": "^4.0.6" + } }, - "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" + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.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==", - "requires": { - "p-limit": "^2.2.0" + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==" + "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==", + "dev": true }, - "parse-filepath": { + "node_modules/regex-not": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, - "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, - "requires": { - "error-ex": "^1.2.0" + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true, - "requires": { - "path-root-regex": "^0.1.0" + "engines": { + "node": ">=0.10.0" } }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "engines": { + "node": ">=0.10" } }, - "pegjs": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.9.0.tgz", - "integrity": "sha1-9q76LjzlYWkgjlIXnf5B+JFBo2k=", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { + "node_modules/repeating": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==", "dev": true, - "requires": { - "pinkie": "^2.0.0" + "dependencies": { + "is-finite": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" + "engines": { + "node": ">= 10" } }, - "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==", + "node_modules/replace-homedir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz", + "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==", "dev": true, - "requires": { - "find-up": "^4.0.0" + "engines": { + "node": ">= 10.13.0" } }, - "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "node_modules/replacestream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", + "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", "dev": true, - "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" + "dependencies": { + "escape-string-regexp": "^1.0.3", + "object-assign": "^4.0.1", + "readable-stream": "^2.0.2" } }, - "pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" + "node_modules/replacestream/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" + } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "node_modules/replacestream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "node_modules/replacestream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "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" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "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" } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "node_modules/replacestream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "pretty-format": { - "version": "27.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", - "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "node_modules/replacestream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "@jest/types": "^27.0.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, "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 - } + "safe-buffer": "~5.1.0" } }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true + "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==", + "engines": { + "node": ">=0.10.0" + } }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "node_modules/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==" }, - "promise-polyfill": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.0.tgz", - "integrity": "sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g==", + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, - "prompts": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", - "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - }, + "node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, "dependencies": { - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } + "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" } }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true, - "optional": true - }, - "psl": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", - "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==", - "dev": true - }, - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "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, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "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" + } }, - "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" - }, + "node_modules/resolve-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz", + "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==", + "dev": true, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "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" - } - }, - "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==" - }, - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" - }, - "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" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "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" - } - }, - "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" - } - } + "value-or-function": "^4.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "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, - "requires": { - "side-channel": "^1.0.4" + "engines": { + "node": ">=10" } }, - "raw-body": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true, - "requires": { - "bytes": "1", - "string_decoder": "0.10" + "engines": { + "node": ">=0.12" } }, - "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "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" } }, - "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "react-popper": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz", - "integrity": "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==", - "requires": { - "react-fast-compare": "^3.0.1", - "warning": "^4.0.2" + "node_modules/rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true, + "engines": { + "node": "6.* || >= 7.*" } }, - "react-redux": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz", - "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==", - "requires": { - "@babel/runtime": "^7.12.1", - "@types/react-redux": "^7.1.16", - "hoist-non-react-statics": "^3.3.2", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-is": "^16.13.1" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "react-shallow-renderer": { - "version": "16.14.1", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz", - "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==", + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, - "requires": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0" + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, - "requires": { - "object-assign": "^4.1.1", - "react-is": "^17.0.2", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" - } + "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/safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", + "dev": true }, - "read-pkg": { + "node_modules/safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "dependencies": { + "ret": "~0.1.10" } }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - } + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "dependencies": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" }, + "bin": { + "sane": "src/cli.js" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/sane/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "node_modules/sane/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "node_modules/sane/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "requires": { - "resolve": "^1.1.6" + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" } }, - "redent": { + "node_modules/sane/node_modules/execa": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" } }, - "redux": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.1.tgz", - "integrity": "sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==", - "requires": { - "@babel/runtime": "^7.9.2" + "node_modules/sane/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "redux-mock-store": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz", - "integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==", + "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, - "requires": { - "lodash.isplainobject": "^4.0.6" + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "redux-thunk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", - "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "node_modules/sane/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "node_modules/sane/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "engines": { + "node": ">=0.10.0" } }, - "remove-bom-buffer": { + "node_modules/sane/node_modules/is-number": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, - "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "node_modules/sane/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, - "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - }, "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "remove-trailing-separator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", - "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=", - "dev": true - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "node_modules/sane/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true, - "requires": { - "is-finite": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", - "dev": true - }, - "replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "node_modules/sane/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - }, "dependencies": { - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - } + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "replacestream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", - "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "node_modules/sane/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "requires": { - "escape-string-regexp": "^1.0.3", - "object-assign": "^4.0.1", - "readable-stream": "^2.0.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "require-directory": { + "node_modules/sane/node_modules/normalize-path": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "resolve": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", - "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, - "requires": { - "path-parse": "^1.0.6" + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.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==", + "node_modules/sane/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dev": true, - "requires": { - "resolve-from": "^5.0.0" + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "node_modules/sane/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "engines": { + "node": ">=4" } }, - "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-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "node_modules/sane/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "requires": { - "value-or-function": "^3.0.0" + "bin": { + "semver": "bin/semver" } }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/sane/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "requires": { - "glob": "^7.1.3" - }, "dependencies": { - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true - }, - "safe-json-parse": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "node_modules/sane/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, - "requires": { - "ret": "~0.1.10" + "engines": { + "node": ">=0.10.0" } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "node_modules/sane/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - } + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true, "optional": true }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, - "requires": { + "dependencies": { "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" } }, - "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "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" + } }, - "semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "node_modules/semver-greatest-satisfied-range": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz", + "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==", "dev": true, - "requires": { - "sver-compat": "^1.5.0" + "dependencies": { + "sver": "^1.8.3" + }, + "engines": { + "node": ">= 10.13.0" } }, - "set-blocking": { + "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=" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "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==", + "dev": true, + "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/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } }, - "set-value": { + "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, - "requires": { + "dependencies": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "shebang-command": { + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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": { + "dependencies": { "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "shebang-regex": { + "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 + "dev": true, + "engines": { + "node": ">=8" + } }, - "shellwords": { + "node_modules/shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "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==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "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" } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "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 }, - "sisteransi": { + "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, - "slash": { + "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "snapdragon": { + "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, - "requires": { + "dependencies": { "base": "^0.11.1", "debug": "^2.2.0", "define-property": "^0.2.5", @@ -8753,142 +13914,137 @@ "source-map-resolve": "^0.5.0", "use": "^3.1.0" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "snapdragon-node": { + "node_modules/snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, - "requires": { + "dependencies": { "define-property": "^1.0.0", "isobject": "^3.0.0", "snapdragon-util": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - } + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "snapdragon-util": { + "node_modules/snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "source-map-resolve": { + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, - "requires": { + "dependencies": { "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", @@ -8896,1063 +14052,1491 @@ "urix": "^0.1.0" } }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "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-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.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, - "requires": { + "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "source-map-url": { + "node_modules/source-map-url": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", "dev": true }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true + "node_modules/sparkles": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz", + "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "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==", "dev": true, - "requires": { + "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "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==", "dev": true }, - "spdx-expression-parse": { + "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "requires": { + "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-license-ids": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", "dev": true }, - "split-string": { + "node_modules/split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, - "requires": { + "dependencies": { "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "sprintf-js": { + "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "stable": { + "node_modules/stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "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, - "requires": { + "dependencies": { "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 - } + "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" } }, - "static-extend": { + "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "dev": true, - "requires": { + "dependencies": { "define-property": "^0.2.5", "object-copy": "^0.1.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-composer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz", + "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==", + "dev": true, + "dependencies": { + "streamx": "^2.13.2" } }, - "stream-exhaust": { + "node_modules/stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", "dev": true }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } }, - "string-length": { + "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, - "requires": { + "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "string-template": { + "node_modules/string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", "dev": true }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "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.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "strip-bom": { + "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 + "dev": true, + "engines": { + "node": ">=8" + } }, - "strip-bom-string": { + "node_modules/strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", - "dev": true + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "strip-eof": { + "node_modules/strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "strip-final-newline": { + "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 + "dev": true, + "engines": { + "node": ">=6" + } }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, - "requires": { - "get-stdin": "^4.0.1" + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-color": { + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { + "dependencies": { "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "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, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "node_modules/sver": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz", + "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==", "dev": true, - "requires": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" + "optionalDependencies": { + "semver": "^6.3.0" } }, - "symbol-tree": { + "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" + "dependencies": { + "streamx": "^2.12.5" } }, - "test-exclude": { + "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, - "requires": { + "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", + "dev": true, "dependencies": { - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "b4a": "^1.6.4" } }, - "textextensions": { + "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/textextensions": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-3.3.0.tgz", "integrity": "sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==", - "dev": true - }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://bevry.me/fund" + } }, - "through2": { + "node_modules/through2": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, - "requires": { - "readable-stream": "3" - }, "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==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - } - } - }, - "through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "dev": true, - "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } + "readable-stream": "3" } }, - "time-stamp": { + "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "node_modules/timers-ext": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", + "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", "dev": true, - "requires": { - "es5-ext": "~0.10.46", - "next-tick": "1" + "dependencies": { + "es5-ext": "^0.10.64", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.12" } }, - "tiny-lr": { + "node_modules/tiny-lr": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", "dev": true, - "requires": { + "dependencies": { "body": "^5.1.0", "debug": "^3.1.0", "faye-websocket": "~0.10.0", "livereload-js": "^2.3.0", "object-assign": "^4.1.0", "qs": "^6.4.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } } }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "node_modules/tiny-lr/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" + "dependencies": { + "ms": "^2.1.1" } }, - "to-fast-properties": { + "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": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } }, - "to-object-path": { + "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex": { + "node_modules/to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, - "requires": { + "dependencies": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "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, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "node_modules/to-through": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz", + "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==", "dev": true, - "requires": { - "through2": "^2.0.3" + "dependencies": { + "streamx": "^2.12.5" }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" } }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, - "requires": { + "dependencies": { "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" } }, - "trim-newlines": { + "node_modules/trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true + "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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" + } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, - "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": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", "dev": true }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "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, - "requires": { - "prelude-ls": "~1.1.2" + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-detect": { + "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 + "dev": true, + "engines": { + "node": ">=4" + } }, - "type-fest": { + "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 + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "typedarray-to-buffer": { + "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, - "requires": { + "dependencies": { "is-typedarray": "^1.0.0" } }, - "typescript": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", - "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", - "dev": true + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", + "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", + "@typescript-eslint/utils": "7.16.0" + }, + "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/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "unc-path-regex": { + "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "undertaker": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", - "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "node_modules/undertaker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz", + "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==", "dev": true, - "requires": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" + "dependencies": { + "bach": "^2.0.1", + "fast-levenshtein": "^3.0.0", + "last-run": "^2.0.0", + "undertaker-registry": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "node_modules/undertaker-registry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz", + "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/undertaker/node_modules/fast-levenshtein": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "dev": true, + "dependencies": { + "fastest-levenshtein": "^1.0.7" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, - "union-value": { + "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, - "requires": { + "dependencies": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, - "requires": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true + "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==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } }, - "unset-value": { + "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, - "requires": { + "dependencies": { "has-value": "^0.3.1", "isobject": "^3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true + "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" + } }, - "urix": { + "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, - "use": { + "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==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "uuid": { + "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } }, - "v8-to-istanbul": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", - "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, - "requires": { + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^2.0.0" }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } + "engines": { + "node": ">=10.12.0" } }, - "v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "node_modules/v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" + "engines": { + "node": ">= 10.13.0" } }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "requires": { + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", - "dev": true + "node_modules/value-or-function": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", + "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "vinyl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", - "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", "dev": true, - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", + "dependencies": { + "clone": "^2.1.2", "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" } }, - "vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "node_modules/vinyl-contents": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", + "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==", "dev": true, - "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", + "dependencies": { + "bl": "^5.0.0", + "vinyl": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-fs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.0.tgz", + "integrity": "sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^2.0.1", + "glob-stream": "^8.0.0", + "graceful-fs": "^4.2.11", + "iconv-lite": "^0.6.3", "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } + "lead": "^4.0.0", + "normalize-path": "3.0.0", + "resolve-options": "^2.0.0", + "stream-composer": "^1.0.2", + "streamx": "^2.14.0", + "to-through": "^3.0.0", + "value-or-function": "^4.0.0", + "vinyl": "^3.0.0", + "vinyl-sourcemap": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "node_modules/vinyl-sourcemap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz", + "integrity": "sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==", "dev": true, - "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" + "dependencies": { + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.10", + "now-and-later": "^3.0.0", + "streamx": "^2.12.5", + "vinyl": "^3.0.0", + "vinyl-contents": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "vinyl-sourcemaps-apply": { + "node_modules/vinyl-sourcemaps-apply": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", "dev": true, - "requires": { - "source-map": "^0.5.1" - }, "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "source-map": "^0.5.1" } }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "node_modules/vinyl-sourcemaps-apply/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" } }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "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, - "requires": { - "makeerror": "1.0.x" + "dependencies": { + "makeerror": "1.0.12" } }, - "warning": { + "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { + "dependencies": { "loose-envify": "^1.0.0" } }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } }, - "websocket-driver": { + "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==", "dev": true, - "requires": { + "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" } }, - "websocket-extensions": { + "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==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, - "requires": { - "iconv-lite": "0.4.24" + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" } }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "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, - "requires": { + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "wrap-ansi": { + "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, - "requires": { + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, - "dependencies": { - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - } + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "write-file-atomic": { + "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, - "requires": { + "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, - "ws": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", - "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", - "dev": true + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": 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 + } + } }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } }, - "xmlchars": { + "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "xtend": { + "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4" + } }, - "y18n": { + "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 + "dev": true, + "engines": { + "node": ">=10" + } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "yargs": { + "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, - "requires": { + "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", @@ -9961,25 +15545,39 @@ "y18n": "^5.0.5", "yargs-parser": "^20.2.2" }, - "dependencies": { - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - } + "engines": { + "node": ">=10" } }, - "yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", - "dev": true + "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/yargs/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/web/package.json b/web/package.json index df4b2b2346..e27056325a 100644 --- a/web/package.json +++ b/web/package.json @@ -2,40 +2,43 @@ "name": "mitmproxy", "private": true, "scripts": { - "test": "tsc --noEmit && jest --coverage", + "test": "eslint . && tsc --noEmit && jest --coverage", "build": "gulp prod", "start": "gulp", - "prettier": "prettier --write ." + "prettier": "prettier --write .", + "eslint": "eslint --fix ." }, "dependencies": { - "@popperjs/core": "^2.9.3", + "@popperjs/core": "^2.11.8", + "@reduxjs/toolkit": "^2.2.5", "bootstrap": "^3.4.1", "classnames": "^2.3.1", "codemirror": "^5.62.3", "lodash": "^4.17.21", "prop-types": "^15.7.2", "qrcode": "^1.5.1", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-popper": "^2.2.5", - "react-redux": "^7.2.4", - "redux": "^4.1.1", - "redux-thunk": "^2.3.0", - "shallowequal": "^1.1.0", + "react-redux": "^9.1.2", "stable": "^0.1.8" }, "devDependencies": { - "@testing-library/dom": "^8.1.0", - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^12.0.0", - "@testing-library/user-event": "^13.2.1", - "@types/jest": "^27.0.1", + "@eslint/js": "^9.6.0", + "@testing-library/dom": "^10.3.1", + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^16.0.0", + "@testing-library/user-event": "^14.5.2", + "@types/jest": "^29.5.12", "@types/redux-mock-store": "^1.0.3", - "esbuild": "^0.12.21", + "esbuild": "^0.23.0", "esbuild-jest": "^0.5.0", - "gulp": "^4.0.2", + "eslint": "^8.57.0", + "eslint-plugin-react": "^7.34.3", + "globals": "^15.8.0", + "gulp": "^5.0.0", "gulp-clean-css": "^4.3.0", - "gulp-esbuild": "^0.8.5", + "gulp-esbuild": "^0.12.0", "gulp-less": "^5.0.0", "gulp-livereload": "^4.0.2", "gulp-notify": "^4.0.0", @@ -43,12 +46,14 @@ "gulp-plumber": "^1.2.1", "gulp-replace": "^1.1.3", "gulp-sourcemaps": "^3.0.0", - "jest": "^27.0.6", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", "jest-fetch-mock": "^3.0.3", - "prettier": "2.8.4", - "react-test-renderer": "^17.0.2", + "prettier": "3.3.2", + "react-test-renderer": "^18.3.1", "redux-mock-store": "^1.5.4", "through2": "^4.0.2", - "typescript": "^4.3.5" + "typescript": "^5.5.3", + "typescript-eslint": "^7.15.0" } } diff --git a/web/src/css/app.less b/web/src/css/app.less index 1f0e3a1537..49084ae714 100644 --- a/web/src/css/app.less +++ b/web/src/css/app.less @@ -24,3 +24,4 @@ html { @import (less) "dropdown.less"; @import (less) "command.less"; @import (less) "capture-setup.less"; +@import (less) "mode.less"; diff --git a/web/src/css/dropdown.less b/web/src/css/dropdown.less index 1ed8ad8e5f..bc1cebd5d2 100644 --- a/web/src/css/dropdown.less +++ b/web/src/css/dropdown.less @@ -5,4 +5,7 @@ > li > a { padding: 3px 10px; } + + max-height: 250px; + overflow-y: scroll; } diff --git a/web/src/css/flowdetail.less b/web/src/css/flowdetail.less index b7f5b8f51a..fa256b749d 100644 --- a/web/src/css/flowdetail.less +++ b/web/src/css/flowdetail.less @@ -21,6 +21,19 @@ } } + .close-button { + margin-top: 2px; + padding-left: 10px; + padding-right: 7px; + color: grey; + font-size: 15px; + border: none; + } + + .close-button:hover { + color: black; + } + .first-line { font-family: @font-family-monospace; background-color: #428bca; @@ -66,7 +79,9 @@ border: solid transparent 1px; &:hover { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 1.25%), 0 2px 4px rgba(0, 0, 0, 5%), + box-shadow: + 0 0 0 1px rgba(0, 0, 0, 1.25%), + 0 2px 4px rgba(0, 0, 0, 5%), 0 2px 6px rgba(0, 0, 0, 2.5%); background-color: rgba(255, 255, 255, 0.1); } @@ -79,7 +94,9 @@ &[contenteditable] { outline-width: 0; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 5%), 0 2px 4px rgba(0, 0, 0, 20%), + box-shadow: + 0 0 0 1px rgba(0, 0, 0, 5%), + 0 2px 4px rgba(0, 0, 0, 20%), 0 2px 6px rgba(0, 0, 0, 10%); background-color: rgba(255, 255, 255, 0.2); diff --git a/web/src/css/flowtable.less b/web/src/css/flowtable.less index e911c9cdc3..d321d6d2a6 100644 --- a/web/src/css/flowtable.less +++ b/web/src/css/flowtable.less @@ -113,6 +113,11 @@ background-color: rgba(0, 185, 0, 0.5); } + .col-index { + text-align: right; + width: 4ch; + } + .col-icon { width: 32px; } @@ -164,9 +169,15 @@ width: 170px; } + .col-comment { + width: 150px; + padding-left: 5px; + } + td.col-time, td.col-size, - td.col-timestamp { + td.col-timestamp, + td.col-comment { text-align: right; } @@ -181,8 +192,7 @@ font-size: 20px; } - tr:hover .col-quickactions, - .col-quickactions.hover { + tr:hover .col-quickactions { overflow: visible; } diff --git a/web/src/css/header.less b/web/src/css/header.less index b890e0b06e..00d696853b 100644 --- a/web/src/css/header.less +++ b/web/src/css/header.less @@ -9,7 +9,7 @@ header { padding-top: 6px; background-color: white; @separator-color: lighten(grey, 15%); - > div { + > div:not(:empty) { display: block; margin: 0; padding: 0; diff --git a/web/src/css/mode.less b/web/src/css/mode.less new file mode 100644 index 0000000000..1a454c8017 --- /dev/null +++ b/web/src/css/mode.less @@ -0,0 +1,315 @@ +@import (reference) "../../node_modules/bootstrap/less/variables.less"; +@import (reference) "../../node_modules/bootstrap/less/mixins/grid.less"; +@import (reference) "../../node_modules/bootstrap/less/mixins/labels.less"; +@import (reference) "../../node_modules/bootstrap/less/labels.less"; + +.modes { + padding: 1em 2em; + overflow-y: auto; + height: 100%; + width: 100vw; + + h3 { + margin-bottom: 10px; + } + + .modes-category { + padding-left: 10px; + } + + .green-left-border { + border-left: 10px solid #77c77a; + } + + .gray-left-border { + border-left: 10px solid #b2b2b2; + } + + .modes-container { + display: flex; + flex-direction: column; + gap: 25px; + } + + .mode-title { + font-size: 16px; + font-weight: 600; + } + + .mode-description { + color: #b2b2b2; + margin-top: -10px; + } + + .mode-entry { + text-align: left; + display: flex; + align-items: center; + font-size: 1.5rem; + font-weight: normal; + margin: 0; + + input[type="checkbox"] { + margin: 0 10px; + vertical-align: middle; + width: 1.8rem; + height: 1.8rem; + } + + p { + margin: 0; + } + } + + .mode-status { + margin-left: 10px; + margin-top: 5px; + font-weight: 600; + } + + .mode-local { + i { + font-size: 1.8rem; + cursor: pointer; + } + .processes-container { + display: flex; + flex-direction: row; + align-items: center; + gap: 5px; + margin-left: 5px; + } + .selected-processes { + display: flex; + flex-wrap: wrap; + gap: 5px; + overflow: hidden; + } + .selected-process { + display: flex; + flex-direction: row; + gap: 5px; + background-color: #e0e0e0; + padding: 5px; + border-radius: 4px; + height: 30px; + font-size: 12px; + font-weight: 500; + align-content: center; + align-items: center; + + > i { + font-size: 15px; + } + } + + .dropdown-container { + display: flex; + flex-direction: row; + align-items: center; + } + + .local-dropdown { + position: relative; + width: 200px; + + .dropdown-header { + padding: 5px; + border: 1px solid #ccc; + border-radius: 4px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + margin-right: 10px; + height: 30px; + } + + input { + border: none; + flex: 1; + outline: none; + color: black; + } + + .dropdown-list { + width: 100%; + max-height: 300px; + overflow-y: auto; + z-index: 1; + list-style: none; + padding: 0; + margin-bottom: 0; + } + + .dropdown-item { + display: flex; + flex-direction: row; + align-items: center; + padding: 8px 10px; + margin: 4px 0; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.2s ease; + } + + .dropdown-item.selected { + background-color: #e0e0e0; + } + + .dropdown-item:hover { + background-color: #f0f0f0; + } + + .process-details { + display: flex; + flex-direction: row; + align-items: center; + } + + .process-icon { + margin-right: 5px; + margin-left: 5px; + color: #5f6368; + width: 25px; + height: 25px; + } + + .process-name { + font-weight: 500; + color: #333; + } + } + + .local-popover { + button { + font-size: 1rem; + } + i { + font-size: 1.5rem; + } + + @supports (anchor-name: --test) { + > div { + margin: 0; + position: absolute; + left: 0; + top: calc(anchor(bottom) + 10px); + justify-self: anchor-center; + align-self: auto; + } + } + + > div { + &:popover-open { + display: block; + } + gap: 0.5rem; + align-items: center; + } + } + } + + .mode-input { + border: 1px solid #ccc; + margin-left: 10px; + border-radius: 4px; + min-width: 120px; + height: 25px; + } + + .mode-reverse-input { + border: 1px solid #ccc; + margin-left: 10px; + margin-right: 10px; + border-radius: 4px; + min-width: 70px; + height: 25px; + } + + .mode-upstream-input { + border: 1px solid #ccc; + margin-left: 10px; + margin-right: 5px; + border-radius: 4px; + min-width: 70px; + height: 25px; + } + + .mode-reverse-dropdown { + margin: 0 5px; + border: 1px solid #ccc; + border-radius: 4px; + height: 25px; + } + + .mode-reverse-servers { + display: flex; + flex-direction: column; + gap: 10px; + } + + .mode-reverse-add-server { + margin-left: 10px; + display: flex; + flex-direction: row; + cursor: pointer; + font-weight: 500; + + opacity: 0.5; + transition: all 50ms ease-in-out; + + &:hover { + opacity: 1; + } + + i { + font-size: 2rem; + margin-right: 5px; + } + } + + .mode-popover { + > button { + background-color: transparent; + border: none; + cursor: pointer; + font-size: 2rem; + } + + @supports (anchor-name: --test) { + > div { + margin: 0; + position: absolute; + left: calc(anchor(right) + 5px); + align-self: anchor-center; + } + } + + > div { + border: 1px solid #ccc; + border-radius: 4px; + padding: 10px 15px; + background-color: #f9f9f9; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + + &:popover-open { + display: grid; + } + grid-template-columns: 9em 1fr; + grid-auto-rows: min-content; + gap: 0.5rem; + align-items: center; + + > h4 { + text-align: center; + grid-column: 1/-1; + } + > .mode-input { + text-align: right; + background-color: white; + margin: 0; + } + } + } +} diff --git a/web/src/css/vendor-bootstrap-variables.less b/web/src/css/vendor-bootstrap-variables.less index 663a87b5f6..77ae785773 100644 --- a/web/src/css/vendor-bootstrap-variables.less +++ b/web/src/css/vendor-bootstrap-variables.less @@ -3,8 +3,19 @@ @navbar-default-color: #303030; @navbar-default-bg: #ffffff; @navbar-default-border: #e0e0e0; -@font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, - "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, - "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +@font-family-sans-serif: + system-ui, + -apple-system, + "Segoe UI", + Roboto, + "Helvetica Neue", + Arial, + "Noto Sans", + "Liberation Sans", + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; @font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; diff --git a/web/src/fonts/font-awesome.css b/web/src/fonts/font-awesome.css index ce2ca1c34b..4a337b18d3 100644 --- a/web/src/fonts/font-awesome.css +++ b/web/src/fonts/font-awesome.css @@ -7,7 +7,8 @@ @font-face { font-family: "FontAwesome"; src: url("./fonts/fontawesome-webfont.eot?v=4.7.0"); - src: url("./fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") + src: + url("./fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"), url("./fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"), url("./fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"), diff --git a/web/src/js/__tests__/backends/staticSpec.tsx b/web/src/js/__tests__/backends/staticSpec.tsx index e892b5aded..59322d5308 100644 --- a/web/src/js/__tests__/backends/staticSpec.tsx +++ b/web/src/js/__tests__/backends/staticSpec.tsx @@ -9,21 +9,9 @@ test("static backend", async () => { fetchMock.mockOnceIf("./flows", "[]"); fetchMock.mockOnceIf("./options", "{}"); const store = TStore(); - const backend = new StaticBackend(store); - await waitFor(() => - expect(store.getActions()).toEqual([ - { - type: "FLOWS_RECEIVE", - cmd: "receive", - data: [], - resource: "flows", - }, - { - type: "OPTIONS_RECEIVE", - cmd: "receive", - data: {}, - resource: "options", - }, - ]) - ); + new StaticBackend(store); + await waitFor(() => { + expect(store.getState().flows.list).toEqual([]); + expect(store.getState().options).toEqual({}); + }); }); diff --git a/web/src/js/__tests__/backends/websocketSpec.tsx b/web/src/js/__tests__/backends/websocketSpec.tsx index 134de711df..3babfb6493 100644 --- a/web/src/js/__tests__/backends/websocketSpec.tsx +++ b/web/src/js/__tests__/backends/websocketSpec.tsx @@ -1,13 +1,13 @@ import { enableFetchMocks } from "jest-fetch-mock"; -import { TStore } from "../ducks/tutils"; import WebSocketBackend from "../../backends/websocket"; import { waitFor } from "../test-utils"; import * as connectionActions from "../../ducks/connection"; +import { UnknownAction } from "@reduxjs/toolkit"; enableFetchMocks(); test("websocket backend", async () => { - // @ts-ignore + // @ts-expect-error jest mock stuff jest.spyOn(global, "WebSocket").mockImplementation(() => ({ addEventListener: () => 0, })); @@ -16,19 +16,18 @@ test("websocket backend", async () => { fetchMock.mockOnceIf("./flows", "[]"); fetchMock.mockOnceIf("./events", "[]"); fetchMock.mockOnceIf("./options", "{}"); - const store = TStore(); - const backend = new WebSocketBackend(store); + + const actions: Array = []; + const backend = new WebSocketBackend({ dispatch: (e) => actions.push(e) }); backend.onOpen(); await waitFor(() => - expect(store.getActions()).toEqual([ + expect(actions).toEqual([ connectionActions.startFetching(), { type: "STATE_RECEIVE", - cmd: "receive", - data: {}, - resource: "state", + payload: {}, }, { type: "FLOWS_RECEIVE", @@ -49,16 +48,16 @@ test("websocket backend", async () => { resource: "options", }, connectionActions.connectionEstablished(), - ]) + ]), ); - store.clearActions(); + actions.length = 0; backend.onMessage({ resource: "events", cmd: "add", data: { id: "42", message: "test", level: "info" }, }); - expect(store.getActions()).toEqual([ + expect(actions).toEqual([ { cmd: "add", data: { id: "42", level: "info", message: "test" }, @@ -66,7 +65,7 @@ test("websocket backend", async () => { type: "EVENTS_ADD", }, ]); - store.clearActions(); + actions.length = 0; fetchMock.mockOnceIf("./events", "[]"); backend.onMessage({ @@ -74,7 +73,7 @@ test("websocket backend", async () => { cmd: "reset", }); await waitFor(() => - expect(store.getActions()).toEqual([ + expect(actions).toEqual([ { type: "EVENTS_RECEIVE", cmd: "receive", @@ -82,21 +81,19 @@ test("websocket backend", async () => { resource: "events", }, connectionActions.connectionEstablished(), - ]) + ]), ); - store.clearActions(); + actions.length = 0; expect(fetchMock.mock.calls).toHaveLength(5); console.error = jest.fn(); backend.onClose(new CloseEvent("Connection closed")); - expect(console.error).toBeCalledTimes(1); - expect(store.getActions()[0].type).toEqual( - connectionActions.ConnectionState.ERROR - ); - store.clearActions(); + expect(console.error).toHaveBeenCalledTimes(1); + expect(actions[0].type).toEqual(connectionActions.ConnectionState.ERROR); + actions.length = 0; backend.onError(null); - expect(console.error).toBeCalledTimes(2); + expect(console.error).toHaveBeenCalledTimes(2); jest.restoreAllMocks(); }); diff --git a/web/src/js/__tests__/components/CaptureSetupSpec.tsx b/web/src/js/__tests__/components/CaptureSetupSpec.tsx deleted file mode 100644 index 9033ed5947..0000000000 --- a/web/src/js/__tests__/components/CaptureSetupSpec.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import * as React from "react"; -import { render } from "../test-utils"; -import CaptureSetup from "../../components/CaptureSetup"; -import { TStore } from "../ducks/tutils"; - -test("CaptureSetup", async () => { - const store = TStore(), - { asFragment } = render(, { store }); - expect(asFragment()).toMatchSnapshot(); -}); diff --git a/web/src/js/__tests__/components/CommandBarSpec.tsx b/web/src/js/__tests__/components/CommandBarSpec.tsx index a418d3ddbf..70f495bba0 100644 --- a/web/src/js/__tests__/components/CommandBarSpec.tsx +++ b/web/src/js/__tests__/components/CommandBarSpec.tsx @@ -48,19 +48,19 @@ test("CommandBar", async () => { return_type: null, signature_help: "flow.encode flows part encoding", }, - }) + }), ); fetchMock.mockOnceIf( "./commands/commands.history.get", - JSON.stringify({ value: ["foo"] }) + JSON.stringify({ value: ["foo"] }), ); fetchMock.mockOnceIf( "./commands/commands.history.add", - JSON.stringify({ value: null }) + JSON.stringify({ value: null }), ); fetchMock.mockOnceIf( "./commands/flow.encode", - JSON.stringify({ value: null }) + JSON.stringify({ value: null }), ); const { asFragment } = render(); @@ -70,29 +70,29 @@ test("CommandBar", async () => { const input = screen.getByPlaceholderText("Enter command"); - userEvent.type(input, "x"); + await userEvent.type(input, "x"); expect(screen.getByText("[]")).toBeInTheDocument(); - userEvent.type(input, "{backspace}"); + await userEvent.type(input, "{backspace}"); - userEvent.type(input, "fl"); - userEvent.tab(); + await userEvent.type(input, "fl"); + await userEvent.tab(); expect(input).toHaveValue("flow.decode"); - userEvent.tab(); + await userEvent.tab(); expect(input).toHaveValue("flow.encode"); fetchMock.mockOnce(JSON.stringify({ value: null })); - userEvent.type(input, "{enter}"); + await userEvent.type(input, "{enter}"); await waitFor(() => screen.getByText("Command Result")); - userEvent.type(input, "{arrowdown}"); + await userEvent.type(input, "{arrowdown}"); expect(input).toHaveValue(""); - userEvent.type(input, "{arrowup}"); + await userEvent.type(input, "{arrowup}"); expect(input).toHaveValue("flow.encode"); - userEvent.type(input, "{arrowup}"); + await userEvent.type(input, "{arrowup}"); expect(input).toHaveValue("foo"); - userEvent.type(input, "{arrowdown}"); + await userEvent.type(input, "{arrowdown}"); expect(input).toHaveValue("flow.encode"); - userEvent.type(input, "{arrowdown}"); + await userEvent.type(input, "{arrowdown}"); expect(input).toHaveValue(""); }); diff --git a/web/src/js/__tests__/components/EventLog/EventListSpec.tsx b/web/src/js/__tests__/components/EventLog/EventListSpec.tsx index 53e5c7f0ae..b217c128bf 100644 --- a/web/src/js/__tests__/components/EventLog/EventListSpec.tsx +++ b/web/src/js/__tests__/components/EventLog/EventListSpec.tsx @@ -1,27 +1,19 @@ import * as React from "react"; import EventLogList from "../../../components/EventLog/EventList"; -import TestUtils from "react-dom/test-utils"; +import { EventLogItem, LogLevel } from "../../../ducks/eventLog"; +import { render } from "../../test-utils"; describe("EventList Component", () => { - let mockEventList = [ - { id: 1, level: "info", message: "foo" }, - { id: 2, level: "error", message: "bar" }, - ], - eventLogList = TestUtils.renderIntoDocument( - - ); + const mockEventList: EventLogItem[] = [ + { id: "1", level: LogLevel.info, message: "foo" }, + { id: "2", level: LogLevel.error, message: "bar" }, + ]; it("should render correctly", () => { - expect(eventLogList.state).toMatchSnapshot(); - expect(eventLogList.props).toMatchSnapshot(); - }); - - it("should handle componentWillUnmount", () => { - window.removeEventListener = jest.fn(); - eventLogList.componentWillUnmount(); - expect(window.removeEventListener).toBeCalledWith( - "resize", - eventLogList.onViewportUpdate + const { asFragment, unmount } = render( + , ); + expect(asFragment()).toMatchSnapshot(); + unmount(); // no errors }); }); diff --git a/web/src/js/__tests__/components/EventLog/__snapshots__/EventListSpec.tsx.snap b/web/src/js/__tests__/components/EventLog/__snapshots__/EventListSpec.tsx.snap index 10bcb59834..3aaed52c6e 100644 --- a/web/src/js/__tests__/components/EventLog/__snapshots__/EventListSpec.tsx.snap +++ b/web/src/js/__tests__/components/EventLog/__snapshots__/EventListSpec.tsx.snap @@ -1,30 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`EventList Component should render correctly 1`] = ` -Object { - "vScroll": Object { - "end": 1, - "paddingBottom": 18, - "paddingTop": 0, - "start": 0, - }, -} -`; - -exports[`EventList Component should render correctly 2`] = ` -Object { - "events": Array [ - Object { - "id": 1, - "level": "info", - "message": "foo", - }, - Object { - "id": 2, - "level": "error", - "message": "bar", - }, - ], - "rowHeight": 18, -} + +
+    
+
+ + foo +
+
+
+
`; diff --git a/web/src/js/__tests__/components/EventLogSpec.tsx b/web/src/js/__tests__/components/EventLogSpec.tsx index 209f2dd319..749a34a6be 100644 --- a/web/src/js/__tests__/components/EventLogSpec.tsx +++ b/web/src/js/__tests__/components/EventLogSpec.tsx @@ -14,7 +14,7 @@ describe("EventLog Component", () => { provider = renderer.create( - + , ), tree = provider.toJSON(); @@ -23,32 +23,32 @@ describe("EventLog Component", () => { }); it("should handle toggleFilter", () => { - let debugToggleButton = tree.children[0].children[1].children[0]; + const debugToggleButton = tree.children[0].children[1].children[0]; debugToggleButton.props.onClick(); }); provider = renderer.create( - + , ); - let eventLog = provider.root.findByType(PureEventLog), - mockEvent = { preventDefault: jest.fn() }; + const eventLog = provider.root.findByType(PureEventLog); + const mockEvent = { preventDefault: jest.fn() }; it("should handle DragStart", () => { eventLog.instance.onDragStart(mockEvent); expect(mockEvent.preventDefault).toBeCalled(); expect(window.addEventListener).toBeCalledWith( "mousemove", - eventLog.instance.onDragMove + eventLog.instance.onDragMove, ); expect(window.addEventListener).toBeCalledWith( "mouseup", - eventLog.instance.onDragStop + eventLog.instance.onDragStop, ); expect(window.addEventListener).toBeCalledWith( "dragend", - eventLog.instance.onDragStop + eventLog.instance.onDragStop, ); mockEvent.preventDefault.mockClear(); }); @@ -65,7 +65,7 @@ describe("EventLog Component", () => { expect(mockEvent.preventDefault).toBeCalled(); expect(window.removeEventListener).toBeCalledWith( "mousemove", - eventLog.instance.onDragMove + eventLog.instance.onDragMove, ); }); }); diff --git a/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.tsx b/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.tsx index cb1d3f1a7a..610ab2d23c 100644 --- a/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.tsx +++ b/web/src/js/__tests__/components/FlowTable/FlowColumnsSpec.tsx @@ -14,7 +14,7 @@ test("should render columns", async () => { - + , ); expect(asFragment()).toMatchSnapshot(name); }); @@ -27,7 +27,7 @@ describe("Flowcolumns Components", () => { tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); - let tflow = { ...TFlow(), websocket: undefined }; + const tflow = { ...TFlow(), websocket: undefined }; iconColumn = renderer.create(); tree = iconColumn.toJSON(); // plain @@ -43,13 +43,13 @@ describe("Flowcolumns Components", () => { tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); // image - let imageFlow = { ...TFlow(), websocket: undefined }; + const imageFlow = { ...TFlow(), websocket: undefined }; imageFlow.response.headers = [["Content-Type", "image/jpeg"]]; iconColumn = renderer.create(); tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); // javascript - let jsFlow = { ...TFlow(), websocket: undefined }; + const jsFlow = { ...TFlow(), websocket: undefined }; jsFlow.response.headers = [ ["Content-Type", "application/x-javascript"], ]; @@ -57,27 +57,27 @@ describe("Flowcolumns Components", () => { tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); // css - let cssFlow = { ...TFlow(), websocket: undefined }; + const cssFlow = { ...TFlow(), websocket: undefined }; cssFlow.response.headers = [["Content-Type", "text/css"]]; iconColumn = renderer.create(); tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); // html - let htmlFlow = { ...TFlow(), websocket: undefined }; + const htmlFlow = { ...TFlow(), websocket: undefined }; htmlFlow.response.headers = [["Content-Type", "text/html"]]; iconColumn = renderer.create(); tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); // default - let fooFlow = { ...TFlow(), websocket: undefined }; + const fooFlow = { ...TFlow(), websocket: undefined }; fooFlow.response.headers = [["Content-Type", "foo"]]; iconColumn = renderer.create(); tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); // no response - let noResponseFlow = { ...TFlow(), response: undefined }; + const noResponseFlow = { ...TFlow(), response: undefined }; iconColumn = renderer.create( - + , ); tree = iconColumn.toJSON(); expect(tree).toMatchSnapshot(); @@ -102,11 +102,20 @@ describe("Flowcolumns Components", () => { tree = timeColumn.toJSON(); expect(tree).toMatchSnapshot(); - let noResponseFlow = { ...tflow, response: undefined }; + const noResponseFlow = { ...tflow, response: undefined }; timeColumn = renderer.create( - + , ); tree = timeColumn.toJSON(); expect(tree).toMatchSnapshot(); }); + + it("should render CommentColumn", () => { + const tflow = TFlow(); + const commentColumn = renderer.create( + , + ); + const tree = commentColumn.toJSON(); + expect(tree).toMatchSnapshot(); + }); }); diff --git a/web/src/js/__tests__/components/FlowTable/FlowRowSpec.tsx b/web/src/js/__tests__/components/FlowTable/FlowRowSpec.tsx index 6f059227f2..284695ee98 100644 --- a/web/src/js/__tests__/components/FlowTable/FlowRowSpec.tsx +++ b/web/src/js/__tests__/components/FlowTable/FlowRowSpec.tsx @@ -1,27 +1,22 @@ import * as React from "react"; import FlowRow from "../../../components/FlowTable/FlowRow"; -import { testState } from "../../ducks/tutils"; import { fireEvent, render, screen } from "../../test-utils"; -import { createAppStore } from "../../../ducks"; +import { TStore } from "../../ducks/tutils"; test("FlowRow", async () => { - const store = createAppStore(testState), - tflow2 = store.getState().flows.list[0], - { asFragment } = render( - - - - -
, - { store } - ); + const store = TStore(); + const tflow = store.getState().flows.list[3]; + const { asFragment } = render( + + + + +
, + { store }, + ); expect(asFragment()).toMatchSnapshot(); - expect(store.getState().flows.selected[0]).not.toBe( - store.getState().flows.list[0].id - ); - fireEvent.click(screen.getByText("http://address:22/path")); - expect(store.getState().flows.selected[0]).toBe( - store.getState().flows.list[0].id - ); + expect(store.getState().flows.selected[0]).not.toBe(tflow.id); + fireEvent.click(screen.getByText("QUERY")); + expect(store.getState().flows.selected[0]).toBe(tflow.id); }); diff --git a/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.tsx b/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.tsx index 00d1810cf1..c7a0256cab 100644 --- a/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.tsx +++ b/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.tsx @@ -3,22 +3,25 @@ import FlowTableHead from "../../../components/FlowTable/FlowTableHead"; import { Provider } from "react-redux"; import { TStore } from "../../ducks/tutils"; import { fireEvent, render, screen } from "@testing-library/react"; -import { setSort } from "../../../ducks/flows"; test("FlowTableHead Component", async () => { - const store = TStore(), - { asFragment } = render( - - - - - -
-
- ); + const store = TStore(); + const { asFragment } = render( + + + + + +
+
, + ); expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("Size")); - - expect(store.getActions()).toStrictEqual([setSort("size", false)]); + expect(store.getState().flows.sort).toEqual({ + column: "size", + desc: false, + }); + fireEvent.click(screen.getByText("Size")); + expect(store.getState().flows.sort).toEqual({ column: "size", desc: true }); }); diff --git a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.tsx.snap b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.tsx.snap index 314deb8fc4..55896842ff 100644 --- a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.tsx.snap +++ b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowColumnsSpec.tsx.snap @@ -1,5 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Flowcolumns Components should render CommentColumn 1`] = ` + + I'm a comment! + +`; + exports[`Flowcolumns Components should render IconColumn 1`] = ` - - + /> http://address:22/path `; @@ -144,13 +150,27 @@ exports[`Flowcolumns Components should render pathColumn 2`] = ` /> - - + /> http://address:22/path `; +exports[`should render columns: comment 1`] = ` + + + + + + + +
+ I'm a comment! +
+
+`; + exports[`should render columns: icon 1`] = ` @@ -169,6 +189,22 @@ exports[`should render columns: icon 1`] = ` `; +exports[`should render columns: index 1`] = ` + +
+ + + + + +
+ 1 +
+
+`; + exports[`should render columns: method 1`] = ` diff --git a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowRowSpec.tsx.snap b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowRowSpec.tsx.snap index 323d075f58..cbf2745006 100644 --- a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowRowSpec.tsx.snap +++ b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowRowSpec.tsx.snap @@ -5,7 +5,7 @@ exports[`FlowRow 1`] = `
+ />
- - http://address:22/path + dns.google A = 8.8.8.8, 8.8.4.4 - WSS + QUERY - 200 + NOERROR - 43b + 8b - 5s + 1s -
- - - -
-
diff --git a/web/src/js/__tests__/components/FlowTableSpec.tsx b/web/src/js/__tests__/components/FlowTableSpec.tsx index 4944fd10bf..c61294218d 100644 --- a/web/src/js/__tests__/components/FlowTableSpec.tsx +++ b/web/src/js/__tests__/components/FlowTableSpec.tsx @@ -1,57 +1,27 @@ import * as React from "react"; -import renderer from "react-test-renderer"; -import { PureFlowTable as FlowTable } from "../../components/FlowTable"; -import TestUtils from "react-dom/test-utils"; -import { TFlow, TStore } from "../ducks/tutils"; -import { Provider } from "react-redux"; +import FlowTable, { PureFlowTable } from "../../components/FlowTable"; + +import { act, render } from "../test-utils"; +import { select } from "../../ducks/flows"; window.addEventListener = jest.fn(); describe("FlowTable Component", () => { - let selectFn = jest.fn(), - tflow = TFlow(), - store = TStore(); - it("should render correctly", () => { - let provider = renderer.create( - - - - ), - tree = provider.toJSON(); - expect(tree).toMatchSnapshot(); + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); }); - let provider = renderer.create( - - - - ), - flowTable = provider.root.findByType(FlowTable); - - it("should handle componentWillUnmount", () => { - flowTable.instance.UNSAFE_componentWillUnmount(); - expect(window.addEventListener).toBeCalledWith( - "resize", - flowTable.instance.onViewportUpdate + it("should scroll current selection into view", () => { + const height = PureFlowTable.defaultProps.rowHeight; + const { asFragment, store } = render( +
+ +
, ); - }); - - it("should handle componentDidUpdate", () => { - // flowTable.shouldScrollIntoView == false - expect(flowTable.instance.componentDidUpdate()).toEqual(undefined); - // rowTop - headHeight < viewportTop - flowTable.instance.shouldScrollIntoView = true; - flowTable.instance.componentDidUpdate(); - // rowBottom > viewportTop + viewportHeight - flowTable.instance.shouldScrollIntoView = true; - flowTable.instance.componentDidUpdate(); - }); + expect(asFragment()).toMatchSnapshot(); - it("should handle componentWillReceiveProps", () => { - flowTable.instance.UNSAFE_componentWillReceiveProps({ - selected: tflow, - }); - expect(flowTable.instance.shouldScrollIntoView).toBeTruthy(); + act(() => store.dispatch(select(store.getState().flows.view[3].id))); + expect(asFragment()).toMatchSnapshot(); }); }); diff --git a/web/src/js/__tests__/components/FlowViewSpec.tsx b/web/src/js/__tests__/components/FlowViewSpec.tsx index 4cf86a3df1..a24807eefe 100644 --- a/web/src/js/__tests__/components/FlowViewSpec.tsx +++ b/web/src/js/__tests__/components/FlowViewSpec.tsx @@ -1,16 +1,15 @@ import * as React from "react"; -import { render, screen } from "../test-utils"; +import { act, fireEvent, render, screen } from "../test-utils"; import FlowView from "../../components/FlowView"; import * as flowActions from "../../ducks/flows"; import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; -import { fireEvent } from "@testing-library/react"; enableFetchMocks(); test("FlowView", async () => { fetchMock.mockReject(new Error("backend missing")); - const { asFragment, store } = render(); + const { asFragment, getByTestId, store } = render(); expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("Response")); @@ -25,10 +24,15 @@ test("FlowView", async () => { fireEvent.click(screen.getByText("Timing")); expect(asFragment()).toMatchSnapshot(); + fireEvent.click(screen.getByText("Comment")); + expect(asFragment()).toMatchSnapshot(); + fireEvent.click(screen.getByText("Error")); expect(asFragment()).toMatchSnapshot(); - store.dispatch(flowActions.select(store.getState().flows.list[2].id)); + act(() => + store.dispatch(flowActions.select(store.getState().flows.list[2].id)), + ); fireEvent.click(screen.getByText("Stream Data")); expect(asFragment()).toMatchSnapshot(); @@ -36,7 +40,9 @@ test("FlowView", async () => { fireEvent.click(screen.getByText("Error")); expect(asFragment()).toMatchSnapshot(); - store.dispatch(flowActions.select(store.getState().flows.list[3].id)); + act(() => + store.dispatch(flowActions.select(store.getState().flows.list[3].id)), + ); fireEvent.click(screen.getByText("Request")); expect(asFragment()).toMatchSnapshot(); @@ -47,11 +53,16 @@ test("FlowView", async () => { fireEvent.click(screen.getByText("Error")); expect(asFragment()).toMatchSnapshot(); - store.dispatch(flowActions.select(store.getState().flows.list[4].id)); + act(() => + store.dispatch(flowActions.select(store.getState().flows.list[4].id)), + ); fireEvent.click(screen.getByText("Datagrams")); expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("Error")); expect(asFragment()).toMatchSnapshot(); + + fireEvent.click(getByTestId("close-button-id")); + expect(store.getState().flows.selected).toEqual([]); }); diff --git a/web/src/js/__tests__/components/Header/CaptureMenuSpec.tsx b/web/src/js/__tests__/components/Header/CaptureMenuSpec.tsx new file mode 100644 index 0000000000..fc67f04e1b --- /dev/null +++ b/web/src/js/__tests__/components/Header/CaptureMenuSpec.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +import CaptureMenu from "../../../components/Header/CaptureMenu"; +import { render } from "../../test-utils"; + +describe("CaptureMenu Component", () => { + it("should render correctly", () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.tsx b/web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.tsx index fb964f3f12..0e631b9d07 100644 --- a/web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.tsx +++ b/web/src/js/__tests__/components/Header/ConnectionIndicatorSpec.tsx @@ -1,21 +1,21 @@ import * as React from "react"; import ConnectionIndicator from "../../../components/Header/ConnectionIndicator"; import * as connectionActions from "../../../ducks/connection"; -import { render } from "../../test-utils"; +import { act, render } from "../../test-utils"; test("ConnectionIndicator", async () => { const { asFragment, store } = render(); expect(asFragment()).toMatchSnapshot(); - store.dispatch(connectionActions.startFetching()); + act(() => store.dispatch(connectionActions.startFetching())); expect(asFragment()).toMatchSnapshot(); - store.dispatch(connectionActions.connectionEstablished()); + act(() => store.dispatch(connectionActions.connectionEstablished())); expect(asFragment()).toMatchSnapshot(); - store.dispatch(connectionActions.connectionError("wat")); + act(() => store.dispatch(connectionActions.connectionError("wat"))); expect(asFragment()).toMatchSnapshot(); - store.dispatch(connectionActions.setOffline()); + act(() => store.dispatch(connectionActions.setOffline())); expect(asFragment()).toMatchSnapshot(); }); diff --git a/web/src/js/__tests__/components/Header/FileMenuSpec.tsx b/web/src/js/__tests__/components/Header/FileMenuSpec.tsx index f25e0e9d9a..d503f2fbca 100644 --- a/web/src/js/__tests__/components/Header/FileMenuSpec.tsx +++ b/web/src/js/__tests__/components/Header/FileMenuSpec.tsx @@ -5,13 +5,13 @@ import { Provider } from "react-redux"; import { TStore } from "../../ducks/tutils"; describe("FileMenu Component", () => { - let store = TStore(), - fileMenu = renderer.create( - - - - ), - tree = fileMenu.toJSON(); + const store = TStore(); + const fileMenu = renderer.create( + + + , + ); + const tree = fileMenu.toJSON(); it("should render correctly", () => { expect(tree).toMatchSnapshot(); diff --git a/web/src/js/__tests__/components/Header/FilterDocsSpec.tsx b/web/src/js/__tests__/components/Header/FilterDocsSpec.tsx index b00d7a4313..a1e48e9d5d 100644 --- a/web/src/js/__tests__/components/Header/FilterDocsSpec.tsx +++ b/web/src/js/__tests__/components/Header/FilterDocsSpec.tsx @@ -13,7 +13,7 @@ test("FilterDocs Component", async () => { ["cmd1", "foo"], ["cmd2", "bar"], ], - }) + }), ); const { asFragment } = render( 0} />); diff --git a/web/src/js/__tests__/components/Header/FilterInputSpec.tsx b/web/src/js/__tests__/components/Header/FilterInputSpec.tsx index 5197152613..2a9e9367ab 100644 --- a/web/src/js/__tests__/components/Header/FilterInputSpec.tsx +++ b/web/src/js/__tests__/components/Header/FilterInputSpec.tsx @@ -2,108 +2,142 @@ import * as React from "react"; import renderer from "react-test-renderer"; import FilterInput from "../../../components/Header/FilterInput"; import FilterDocs from "../../../components/Header/FilterDocs"; -import TestUtil from "react-dom/test-utils"; -import ReactDOM from "react-dom"; +import { act, render } from "../../test-utils"; describe("FilterInput Component", () => { it("should render correctly", () => { - let filterInput = renderer.create( - undefined} - value="42" - /> - ), - tree = filterInput.toJSON(); + const filterInput = renderer.create( + undefined} + value="42" + />, + ); + const tree = filterInput.toJSON(); expect(tree).toMatchSnapshot(); }); - let filterInput = TestUtil.renderIntoDocument( - - ); + function dummyInput(): FilterInput { + const ref = React.createRef(); + render( + , + ); + return ref.current!; + } + it("should handle componentWillReceiveProps", () => { - filterInput.UNSAFE_componentWillReceiveProps({ value: "foo" }); - expect(filterInput.state.value).toEqual("foo"); + const { rerender, getByDisplayValue } = render( + null} + />, + ); + rerender( + null} + />, + ); + expect(getByDisplayValue("bar")).toBeInTheDocument(); }); it("should handle isValid", () => { + const filterInput = dummyInput(); // valid expect(filterInput.isValid("~u foo")).toBeTruthy(); expect(filterInput.isValid("~foo bar")).toBeFalsy(); }); it("should handle getDesc", () => { - filterInput.state.value = ""; + const filterInput = dummyInput(); + + act(() => filterInput.setState({ value: "" })); expect(filterInput.getDesc().type).toEqual(FilterDocs); - filterInput.state.value = "~u foo"; + act(() => filterInput.setState({ value: "~u foo" })); expect(filterInput.getDesc()).toEqual("url matches /foo/i"); - filterInput.state.value = "~foo bar"; + act(() => filterInput.setState({ value: "~foo bar" })); expect(filterInput.getDesc()).toEqual( - 'SyntaxError: Expected filter expression but "~" found.' + 'SyntaxError: Expected filter expression but "~" found.', ); }); it("should handle change", () => { - let mockEvent = { target: { value: "~a bar" } }; - filterInput.onChange(mockEvent); + const filterInput = dummyInput(); + const mockEvent = { target: { value: "~a bar" } }; + act(() => filterInput.onChange(mockEvent)); expect(filterInput.state.value).toEqual("~a bar"); expect(filterInput.props.onChange).toBeCalledWith("~a bar"); }); it("should handle focus", () => { - filterInput.onFocus(); + const filterInput = dummyInput(); + act(() => filterInput.onFocus()); expect(filterInput.state.focus).toBeTruthy(); }); it("should handle blur", () => { - filterInput.onBlur(); + const filterInput = dummyInput(); + act(() => filterInput.onBlur()); expect(filterInput.state.focus).toBeFalsy(); }); it("should handle mouseEnter", () => { - filterInput.onMouseEnter(); + const filterInput = dummyInput(); + act(() => filterInput.onMouseEnter()); expect(filterInput.state.mousefocus).toBeTruthy(); }); it("should handle mouseLeave", () => { - filterInput.onMouseLeave(); + const filterInput = dummyInput(); + act(() => filterInput.onMouseLeave()); expect(filterInput.state.mousefocus).toBeFalsy(); }); - let input = ReactDOM.findDOMNode(filterInput.refs.input); - it("should handle keyDown", () => { + const filterInput = dummyInput(); + const input = filterInput.inputRef.current!; input.blur = jest.fn(); - let mockEvent = { + const mockEvent = { key: "Escape", stopPropagation: jest.fn(), }; - filterInput.onKeyDown(mockEvent); + act(() => filterInput.onKeyDown(mockEvent)); expect(input.blur).toBeCalled(); expect(filterInput.state.mousefocus).toBeFalsy(); expect(mockEvent.stopPropagation).toBeCalled(); }); it("should handle selectFilter", () => { + const filterInput = dummyInput(); + const input = filterInput.inputRef.current!; input.focus = jest.fn(); - filterInput.selectFilter("bar"); + act(() => filterInput.selectFilter("bar")); expect(filterInput.state.value).toEqual("bar"); expect(input.focus).toBeCalled(); }); it("should handle select", () => { + const filterInput = dummyInput(); + const input = filterInput.inputRef.current!; input.select = jest.fn(); - filterInput.select(); + act(() => filterInput.select()); expect(input.select).toBeCalled(); }); }); diff --git a/web/src/js/__tests__/components/Header/MainMenuSpec.tsx b/web/src/js/__tests__/components/Header/MainMenuSpec.tsx index 723d7c9f79..81ba480da8 100644 --- a/web/src/js/__tests__/components/Header/MainMenuSpec.tsx +++ b/web/src/js/__tests__/components/Header/MainMenuSpec.tsx @@ -1,8 +1,8 @@ import * as React from "react"; -import StartMenu from "../../../components/Header/StartMenu"; +import FlowListMenu from "../../../components/Header/FlowListMenu"; import { render } from "../../test-utils"; test("MainMenu", () => { - const { asFragment } = render(); + const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); diff --git a/web/src/js/__tests__/components/Header/MenuToggleSpec.tsx b/web/src/js/__tests__/components/Header/MenuToggleSpec.tsx index 1b3d5cd6da..342068a977 100644 --- a/web/src/js/__tests__/components/Header/MenuToggleSpec.tsx +++ b/web/src/js/__tests__/components/Header/MenuToggleSpec.tsx @@ -5,37 +5,40 @@ import { MenuToggle, OptionsToggle, } from "../../../components/Header/MenuToggle"; -import { Provider } from "react-redux"; -import { TStore } from "../../ducks/tutils"; -import * as optionsEditorActions from "../../../ducks/ui/optionsEditor"; -import { fireEvent, render, screen } from "../../test-utils"; +import { fireEvent, render, screen, waitFor } from "../../test-utils"; + +import { enableFetchMocks } from "jest-fetch-mock"; + +enableFetchMocks(); describe("MenuToggle Component", () => { it("should render correctly", () => { - let changeFn = jest.fn(), - menuToggle = renderer.create( - -

foo children

-
- ), - tree = menuToggle.toJSON(); + const changeFn = jest.fn(); + const menuToggle = renderer.create( + +

foo children

+
, + ); + const tree = menuToggle.toJSON(); expect(tree).toMatchSnapshot(); }); }); test("OptionsToggle", async () => { - const store = TStore(), - { asFragment } = render( - toggle anticache, - { store } - ); - globalThis.fetch = jest.fn(); + fetchMock.mockReject(new Error("backend missing")); + + const { asFragment, store } = render( + toggle anticache, + ); expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("toggle anticache")); - expect(store.getActions()).toEqual([ - optionsEditorActions.startUpdate("anticache", true), - ]); + + await waitFor(() => + expect(store.getState().ui.optionsEditor.anticache?.error).toContain( + "backend missing", + ), + ); }); test("EventlogToggle", async () => { diff --git a/web/src/js/__tests__/components/Header/OptionMenuSpec.tsx b/web/src/js/__tests__/components/Header/OptionMenuSpec.tsx index a07c8f082a..421fd9e637 100644 --- a/web/src/js/__tests__/components/Header/OptionMenuSpec.tsx +++ b/web/src/js/__tests__/components/Header/OptionMenuSpec.tsx @@ -6,13 +6,13 @@ import { TStore } from "../../ducks/tutils"; describe("OptionMenu Component", () => { it("should render correctly", () => { - let store = TStore(), - provider = renderer.create( - - - - ), - tree = provider.toJSON(); + const store = TStore(); + const provider = renderer.create( + + + , + ); + const tree = provider.toJSON(); expect(tree).toMatchSnapshot(); }); }); diff --git a/web/src/js/__tests__/components/Header/__snapshots__/CaptureMenuSpec.tsx.snap b/web/src/js/__tests__/components/Header/__snapshots__/CaptureMenuSpec.tsx.snap new file mode 100644 index 0000000000..ac46e8f8a2 --- /dev/null +++ b/web/src/js/__tests__/components/Header/__snapshots__/CaptureMenuSpec.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CaptureMenu Component should render correctly 1`] = ``; diff --git a/web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.tsx.snap b/web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.tsx.snap index b573d8b515..a26fe8c253 100644 --- a/web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.tsx.snap +++ b/web/src/js/__tests__/components/Header/__snapshots__/FilterDocsSpec.tsx.snap @@ -36,6 +36,7 @@ exports[`FilterDocs Component 2`] = ` > { const { asFragment } = render(
); + expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("Options")); @@ -17,4 +17,7 @@ test("Header", async () => { fireEvent.click(screen.getByText("File")); expect(screen.queryByText("Open...")).toBeNull(); + + fireEvent.click(screen.getByText("Capture")); + expect(asFragment()).toMatchSnapshot(); }); diff --git a/web/src/js/__tests__/components/Modal/ModalSpec.tsx b/web/src/js/__tests__/components/Modal/ModalSpec.tsx index fea1f258bc..ccf6619a9d 100644 --- a/web/src/js/__tests__/components/Modal/ModalSpec.tsx +++ b/web/src/js/__tests__/components/Modal/ModalSpec.tsx @@ -1,12 +1,12 @@ import * as React from "react"; import Modal from "../../../components/Modal/Modal"; -import { render } from "../../test-utils"; +import { render, act } from "../../test-utils"; import { setActiveModal } from "../../../ducks/ui/modal"; test("Modal Component", async () => { const { asFragment, store } = render(); expect(asFragment()).toMatchSnapshot(); - store.dispatch(setActiveModal("OptionModal")); + act(() => store.dispatch(setActiveModal("OptionModal"))); expect(asFragment()).toMatchSnapshot(); }); diff --git a/web/src/js/__tests__/components/Modal/OptionModalSpec.tsx b/web/src/js/__tests__/components/Modal/OptionModalSpec.tsx index 4316a519d6..4f7a59556f 100644 --- a/web/src/js/__tests__/components/Modal/OptionModalSpec.tsx +++ b/web/src/js/__tests__/components/Modal/OptionModalSpec.tsx @@ -4,18 +4,18 @@ import { PureOptionDefault } from "../../../components/Modal/OptionModal"; describe("PureOptionDefault Component", () => { it("should return null when the value is default", () => { - let pureOptionDefault = renderer.create( - - ), - tree = pureOptionDefault.toJSON(); + const pureOptionDefault = renderer.create( + , + ); + const tree = pureOptionDefault.toJSON(); expect(tree).toMatchSnapshot(); }); it("should handle boolean type", () => { - let pureOptionDefault = renderer.create( - - ), - tree = pureOptionDefault.toJSON(); + const pureOptionDefault = renderer.create( + , + ); + const tree = pureOptionDefault.toJSON(); expect(tree).toMatchSnapshot(); }); @@ -24,31 +24,31 @@ describe("PureOptionDefault Component", () => { b = [], c = ["c"], pureOptionDefault = renderer.create( - + , ), tree = pureOptionDefault.toJSON(); expect(tree).toMatchSnapshot(); pureOptionDefault = renderer.create( - + , ); tree = pureOptionDefault.toJSON(); expect(tree).toMatchSnapshot(); }); it("should handle string", () => { - let pureOptionDefault = renderer.create( - - ), - tree = pureOptionDefault.toJSON(); + const pureOptionDefault = renderer.create( + , + ); + const tree = pureOptionDefault.toJSON(); expect(tree).toMatchSnapshot(); }); it("should handle null value", () => { - let pureOptionDefault = renderer.create( - - ), - tree = pureOptionDefault.toJSON(); + const pureOptionDefault = renderer.create( + , + ); + const tree = pureOptionDefault.toJSON(); expect(tree).toMatchSnapshot(); }); }); diff --git a/web/src/js/__tests__/components/Modal/OptionSpec.tsx b/web/src/js/__tests__/components/Modal/OptionSpec.tsx index 47540f73db..942dff6c3c 100644 --- a/web/src/js/__tests__/components/Modal/OptionSpec.tsx +++ b/web/src/js/__tests__/components/Modal/OptionSpec.tsx @@ -1,102 +1,102 @@ import * as React from "react"; -import renderer from "react-test-renderer"; -import { Options, ChoicesOption } from "../../../components/Modal/Option"; +import renderer, { act } from "react-test-renderer"; +import { ChoicesOption, Options } from "../../../components/Modal/OptionInput"; describe("BooleanOption Component", () => { - let BooleanOption = Options["bool"], - onChangeFn = jest.fn(), - booleanOption = renderer.create( - - ), - tree = booleanOption.toJSON(); + const BooleanOption = Options["bool"]; + const onChangeFn = jest.fn(); + const booleanOption = renderer.create( + , + ); + const tree = booleanOption.toJSON(); it("should render correctly", () => { expect(tree).toMatchSnapshot(); }); it("should handle onChange", () => { - let input = tree.children[0].children[0], - mockEvent = { target: { checked: true } }; + const input = tree.children[0].children[0]; + const mockEvent = { target: { checked: true } }; input.props.onChange(mockEvent); expect(onChangeFn).toBeCalledWith(mockEvent.target.checked); }); }); describe("StringOption Component", () => { - let StringOption = Options["str"], - onChangeFn = jest.fn(), - stringOption = renderer.create( - - ), - tree = stringOption.toJSON(); + const StringOption = Options["str"]; + const onChangeFn = jest.fn(); + const stringOption = renderer.create( + , + ); + const tree = stringOption.toJSON(); it("should render correctly", () => { expect(tree).toMatchSnapshot(); }); it("should handle onChange", () => { - let mockEvent = { target: { value: "bar" } }; + const mockEvent = { target: { value: "bar" } }; tree.props.onChange(mockEvent); expect(onChangeFn).toBeCalledWith(mockEvent.target.value); }); }); describe("NumberOption Component", () => { - let NumberOption = Options["int"], - onChangeFn = jest.fn(), - numberOption = renderer.create( - - ), - tree = numberOption.toJSON(); + const NumberOption = Options["int"]; + const onChangeFn = jest.fn(); + const numberOption = renderer.create( + , + ); + const tree = numberOption.toJSON(); it("should render correctly", () => { expect(tree).toMatchSnapshot(); }); it("should handle onChange", () => { - let mockEvent = { target: { value: "2" } }; + const mockEvent = { target: { value: "2" } }; tree.props.onChange(mockEvent); expect(onChangeFn).toBeCalledWith(2); }); }); describe("ChoiceOption Component", () => { - let onChangeFn = jest.fn(), - choiceOption = renderer.create( - - ), - tree = choiceOption.toJSON(); + const onChangeFn = jest.fn(); + const choiceOption = renderer.create( + , + ); + const tree = choiceOption.toJSON(); it("should render correctly", () => { expect(tree).toMatchSnapshot(); }); it("should handle onChange", () => { - let mockEvent = { target: { value: "b" } }; + const mockEvent = { target: { value: "b" } }; tree.props.onChange(mockEvent); expect(onChangeFn).toBeCalledWith(mockEvent.target.value); }); }); describe("StringOption Component", () => { - let onChangeFn = jest.fn(), - StringSequenceOption = Options["sequence of str"], - stringSequenceOption = renderer.create( - - ), - tree = stringSequenceOption.toJSON(); + const onChangeFn = jest.fn(); + const StringSequenceOption = Options["sequence of str"]; + const stringSequenceOption = renderer.create( + , + ); + const tree = stringSequenceOption.toJSON(); it("should render correctly", () => { expect(tree).toMatchSnapshot(); }); it("should handle onChange", () => { - let mockEvent = { target: { value: "a\nb\nc\n" } }; - tree.props.onChange(mockEvent); - expect(onChangeFn).toBeCalledWith(["a", "b", "c", ""]); + const mockEvent = { target: { value: "a\nb\nc\n" } }; + act(() => tree.props.onChange(mockEvent)); + expect(onChangeFn).toBeCalledWith(["a", "b", "c"]); }); }); diff --git a/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.tsx.snap b/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.tsx.snap index 3a0c54b2f5..892bae892f 100644 --- a/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.tsx.snap +++ b/web/src/js/__tests__/components/Modal/__snapshots__/ModalSpec.tsx.snap @@ -81,6 +81,7 @@ exports[`Modal Component 2`] = ` >
+
+ + - 5s - - - - -
-
-
+ + + + + Path + + + Method + + + Status + + + Size + + + Time + + + + + + + + + +
+ + + + + dns.google A = 8.8.8.8, 8.8.4.4 + + + QUERY + + + NOERROR + + + 8b + + + 1s + + + + + + +
+ + + + + 127.0.0.1:22 ↔ address:22 + + + UDP + + + + 12b + + + 5s + + + + + + +
+
+ `; diff --git a/web/src/js/__tests__/components/__snapshots__/FlowViewSpec.tsx.snap b/web/src/js/__tests__/components/__snapshots__/FlowViewSpec.tsx.snap index c748ffd718..b15f441f10 100644 --- a/web/src/js/__tests__/components/__snapshots__/FlowViewSpec.tsx.snap +++ b/web/src/js/__tests__/components/__snapshots__/FlowViewSpec.tsx.snap @@ -8,6 +8,14 @@ exports[`FlowView 1`] = `
+ Timing + + Comment +
+ Timing + + Comment +
+ Timing + + Comment +
+ Timing + + Comment +
+ + + Request + + + Response + + + WebSocket + + + Error + + + Connection + + + Timing + + + Comment + + +
+

+ Comment +

+ + I'm a comment! + +
+
+ +`; + +exports[`FlowView 7`] = ` + +
+
`; -exports[`FlowView 7`] = ` +exports[`FlowView 8`] = `
+ Timing + + Comment +
`; -exports[`FlowView 8`] = ` +exports[`FlowView 9`] = `
+ Timing + + Comment +
`; -exports[`FlowView 9`] = ` +exports[`FlowView 10`] = `
+ Timing + + Comment +
`; -exports[`FlowView 10`] = ` +exports[`FlowView 11`] = `
+ Timing + + Comment +
`; -exports[`FlowView 11`] = ` +exports[`FlowView 12`] = `
+ Timing + + Comment +
`; -exports[`FlowView 12`] = ` +exports[`FlowView 13`] = `
+ Timing + + Comment +
`; -exports[`FlowView 13`] = ` +exports[`FlowView 14`] = `
+ Timing + + Comment +
- Start + Capture + + + Flow List - Start + Capture + + + Flow List - Start + Capture + + + Flow List `; + +exports[`Header 4`] = ` + +
+ +
+
+ +`; diff --git a/web/src/js/__tests__/components/common/ButtonSpec.tsx b/web/src/js/__tests__/components/common/ButtonSpec.tsx index 802073565a..b72273fc84 100644 --- a/web/src/js/__tests__/components/common/ButtonSpec.tsx +++ b/web/src/js/__tests__/components/common/ButtonSpec.tsx @@ -4,31 +4,27 @@ import Button from "../../../components/common/Button"; describe("Button Component", () => { it("should render correctly", () => { - let button = renderer.create( - - ), - tree = button.toJSON(); + const button = renderer.create( + , + ); + const tree = button.toJSON(); expect(tree).toMatchSnapshot(); }); it("should be able to be disabled", () => { - let button = renderer.create( - - ), - tree = button.toJSON(); + const button = renderer.create( + , + ); + const tree = button.toJSON(); expect(tree).toMatchSnapshot(); }); }); diff --git a/web/src/js/__tests__/components/common/DocsLinkSpec.tsx b/web/src/js/__tests__/components/common/DocsLinkSpec.tsx index ccd8c3f993..f22c3e65ee 100644 --- a/web/src/js/__tests__/components/common/DocsLinkSpec.tsx +++ b/web/src/js/__tests__/components/common/DocsLinkSpec.tsx @@ -4,16 +4,16 @@ import DocsLink from "../../../components/common/DocsLink"; describe("DocsLink Component", () => { it("should be able to be rendered with children nodes", () => { - let docsLink = renderer.create( - - ), - tree = docsLink.toJSON(); + const docsLink = renderer.create( + foo, + ); + const tree = docsLink.toJSON(); expect(tree).toMatchSnapshot(); }); it("should be able to be rendered without children nodes", () => { - let docsLink = renderer.create(), - tree = docsLink.toJSON(); + const docsLink = renderer.create(); + const tree = docsLink.toJSON(); expect(tree).toMatchSnapshot(); }); }); diff --git a/web/src/js/__tests__/components/common/DropdownSpec.tsx b/web/src/js/__tests__/components/common/DropdownSpec.tsx index 590aae2f82..27455bcbef 100644 --- a/web/src/js/__tests__/components/common/DropdownSpec.tsx +++ b/web/src/js/__tests__/components/common/DropdownSpec.tsx @@ -7,13 +7,13 @@ import Dropdown, { import { fireEvent, render, screen, waitFor } from "../../test-utils"; test("Dropdown", async () => { - let onOpen = jest.fn(); + const onOpen = jest.fn(); const { asFragment } = render( 0}>click me 0}>click me - + , ); expect(asFragment()).toMatchSnapshot(); @@ -30,7 +30,7 @@ test("SubMenu", async () => { const { asFragment } = render( 0}>click me - + , ); expect(asFragment()).toMatchSnapshot(); @@ -44,7 +44,7 @@ test("SubMenu", async () => { }); test("MenuItem", async () => { - let click = jest.fn(); + const click = jest.fn(); const { asFragment } = render(wtf); expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("wtf")); diff --git a/web/src/js/__tests__/components/common/FileChooserSpec.tsx b/web/src/js/__tests__/components/common/FileChooserSpec.tsx index 77fc2af6a6..7cdb21cc5d 100644 --- a/web/src/js/__tests__/components/common/FileChooserSpec.tsx +++ b/web/src/js/__tests__/components/common/FileChooserSpec.tsx @@ -4,7 +4,7 @@ import { render } from "@testing-library/react"; test("FileChooser", async () => { const { asFragment } = render( - 0} /> + 0} />, ); expect(asFragment()).toMatchSnapshot(); diff --git a/web/src/js/__tests__/components/common/SplitterSpec.tsx b/web/src/js/__tests__/components/common/SplitterSpec.tsx index 488656d91e..5ef9af2461 100644 --- a/web/src/js/__tests__/components/common/SplitterSpec.tsx +++ b/web/src/js/__tests__/components/common/SplitterSpec.tsx @@ -1,105 +1,51 @@ import * as React from "react"; -import ReactDOM from "react-dom"; -import renderer from "react-test-renderer"; import Splitter from "../../../components/common/Splitter"; -import TestUtils from "react-dom/test-utils"; - -describe("Splitter Component", () => { - it("should render correctly", () => { - let splitter = renderer.create(), - tree = splitter.toJSON(); - expect(tree).toMatchSnapshot(); - }); - - let splitter = TestUtils.renderIntoDocument(), - dom = ReactDOM.findDOMNode(splitter), - previousElementSibling = { - offsetHeight: 0, - offsetWidth: 0, - style: { flex: "" }, - }, - nextElementSibling = { - style: { flex: "" }, - }; - - it("should handle mouseDown ", () => { - window.addEventListener = jest.fn(); - splitter.onMouseDown({ pageX: 1, pageY: 2 }); - expect(splitter.state.startX).toEqual(1); - expect(splitter.state.startY).toEqual(2); - expect(window.addEventListener).toBeCalledWith( - "mousemove", - splitter.onMouseMove - ); - expect(window.addEventListener).toBeCalledWith( - "mouseup", - splitter.onMouseUp - ); - expect(window.addEventListener).toBeCalledWith( - "dragend", - splitter.onDragEnd +import { act, render } from "../../test-utils"; + +describe.each([["x"], ["y"]])("Splitter Component", (axis) => { + it(`should render correctly (${axis} axis)`, () => { + const ref = React.createRef(); + const { asFragment, unmount } = render( + <> +
+ +
+ , ); - }); - - it("should handle dragEnd", () => { - window.removeEventListener = jest.fn(); - splitter.onDragEnd(); - expect(dom.style.transform).toEqual(""); - expect(window.removeEventListener).toBeCalledWith( - "dragend", - splitter.onDragEnd - ); - expect(window.removeEventListener).toBeCalledWith( - "mouseup", - splitter.onMouseUp - ); - expect(window.removeEventListener).toBeCalledWith( - "mousemove", - splitter.onMouseMove - ); - }); - - it("should handle mouseUp", () => { - Object.defineProperty(dom, "previousElementSibling", { - value: previousElementSibling, + const splitter = ref.current!; + + expect(asFragment()).toMatchSnapshot(); + + act(() => { + splitter.onPointerDown({ + target: { + setPointerCapture: () => 0, + } as unknown, + pageX: 100, + pageY: 200, + pointerId: 42, + } as React.PointerEvent); }); - Object.defineProperty(dom, "nextElementSibling", { - value: nextElementSibling, + expect(splitter.state.startPos).toBe(axis === "x" ? 100 : 200); + + act(() => { + splitter.onPointerMove({ + pageX: 300, + pageY: 300, + pointerId: 42, + } as React.PointerEvent); }); - splitter.onMouseUp({ pageX: 3, pageY: 4 }); - expect(splitter.state.applied).toBeTruthy(); - expect(nextElementSibling.style.flex).toEqual("1 1 auto"); - expect(previousElementSibling.style.flex).toEqual("0 0 2px"); - }); - - it("should handle mouseMove", () => { - splitter.onMouseMove({ pageX: 10, pageY: 10 }); - expect(dom.style.transform).toEqual("translate(9px, 0px)"); - - let splitterY = TestUtils.renderIntoDocument(); - splitterY.onMouseMove({ pageX: 10, pageY: 10 }); - expect(ReactDOM.findDOMNode(splitterY).style.transform).toEqual( - "translate(0px, 10px)" - ); - }); - - it("should handle resize", () => { - let x = jest.spyOn(window, "setTimeout"); - splitter.onResize(); - expect(x).toHaveBeenCalled(); - }); - - it("should handle componentWillUnmount", () => { - splitter.componentWillUnmount(); - expect(previousElementSibling.style.flex).toEqual(""); - expect(nextElementSibling.style.flex).toEqual(""); - expect(splitter.state.applied).toBeTruthy(); - }); - - it("should handle reset", () => { - splitter.reset(false); - expect(splitter.state.applied).toBeFalsy(); + expect(splitter.node.current!.style.transform).toBeTruthy(); + + act(() => { + splitter.onLostPointerCapture({ + pageX: 400, + pageY: 400, + pointerId: 42, + } as React.PointerEvent); + }); + expect(asFragment()).toMatchSnapshot(); - expect(splitter.reset(true)).toEqual(undefined); + unmount(); }); }); diff --git a/web/src/js/__tests__/components/common/ToggleButtonSpec.tsx b/web/src/js/__tests__/components/common/ToggleButtonSpec.tsx index 62e0d0e08d..0e249f481f 100644 --- a/web/src/js/__tests__/components/common/ToggleButtonSpec.tsx +++ b/web/src/js/__tests__/components/common/ToggleButtonSpec.tsx @@ -3,21 +3,21 @@ import renderer from "react-test-renderer"; import ToggleButton from "../../../components/common/ToggleButton"; describe("ToggleButton Component", () => { - let mockFunc = jest.fn(); + const mockFunc = jest.fn(); it("should render correctly", () => { - let checkedButton = renderer.create( - - ), - tree = checkedButton.toJSON(); + const checkedButton = renderer.create( + , + ); + const tree = checkedButton.toJSON(); expect(tree).toMatchSnapshot(); }); it("should handle click action", () => { - let uncheckButton = renderer.create( - - ), - tree = uncheckButton.toJSON(); + const uncheckButton = renderer.create( + , + ); + const tree = uncheckButton.toJSON(); tree.props.onClick(); expect(mockFunc).toBeCalled(); }); diff --git a/web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.tsx.snap b/web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.tsx.snap index becd2b9045..1cda6e8a6f 100644 --- a/web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.tsx.snap +++ b/web/src/js/__tests__/components/common/__snapshots__/DocsLinkSpec.tsx.snap @@ -3,6 +3,7 @@ exports[`DocsLink Component should be able to be rendered with children nodes 1`] = ` foo @@ -12,6 +13,7 @@ exports[`DocsLink Component should be able to be rendered with children nodes 1` exports[`DocsLink Component should be able to be rendered without children nodes 1`] = ` +exports[`Splitter Component should render correctly (x axis) 1`] = ` + +
+
+
+
+ +`; + +exports[`Splitter Component should render correctly (x axis) 2`] = ` + +
+
+
+
+
+ +`; + +exports[`Splitter Component should render correctly (y axis) 1`] = ` + +
+
+
+
+
+ +`; + +exports[`Splitter Component should render correctly (y axis) 2`] = ` + +
+
+
+
+
-
+ `; diff --git a/web/src/js/__tests__/components/contentviews/HttpMessageSpec.tsx b/web/src/js/__tests__/components/contentviews/HttpMessageSpec.tsx index 74ed7d015b..eb440dc3c0 100644 --- a/web/src/js/__tests__/components/contentviews/HttpMessageSpec.tsx +++ b/web/src/js/__tests__/components/contentviews/HttpMessageSpec.tsx @@ -32,12 +32,12 @@ test("HttpMessage", async () => { JSON.stringify({ lines: Array(5).fill([["text", "rawdata"]]), description: "Raw", - }) + }), ); const tflow = TFlow(); const { asFragment } = render( - + , ); await waitFor(() => screen.getAllByText("data")); expect(screen.queryByText("additional")).toBeNull(); @@ -61,7 +61,7 @@ test("HttpMessage", async () => { test("ViewImage", async () => { const flow = TFlow(); const { asFragment } = render( - + , ); expect(asFragment()).toMatchSnapshot(); }); diff --git a/web/src/js/__tests__/components/contentviews/LineRendererSpec.tsx b/web/src/js/__tests__/components/contentviews/LineRendererSpec.tsx index 551402a7f9..e1fcd5f842 100644 --- a/web/src/js/__tests__/components/contentviews/LineRendererSpec.tsx +++ b/web/src/js/__tests__/components/contentviews/LineRendererSpec.tsx @@ -16,7 +16,7 @@ test("LineRenderer", async () => { const showMore = jest.fn(); const { asFragment } = render( - + , ); expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("Show more")); @@ -25,7 +25,7 @@ test("LineRenderer", async () => { test("No lines", async () => { const { asFragment } = render( - 0} /> + 0} />, ); expect(asFragment()).toMatchSnapshot(); }); diff --git a/web/src/js/__tests__/components/contentviews/ViewSelectorSpec.tsx b/web/src/js/__tests__/components/contentviews/ViewSelectorSpec.tsx index 8e36a4e7c5..6450fb96f3 100644 --- a/web/src/js/__tests__/components/contentviews/ViewSelectorSpec.tsx +++ b/web/src/js/__tests__/components/contentviews/ViewSelectorSpec.tsx @@ -5,7 +5,7 @@ import { fireEvent, render, screen } from "../../test-utils"; test("ViewSelector", async () => { const onChange = jest.fn(); const { asFragment } = render( - + , ); expect(asFragment()).toMatchSnapshot(); fireEvent.click(screen.getByText("auto")); diff --git a/web/src/js/__tests__/components/contentviews/useContentSpec.tsx b/web/src/js/__tests__/components/contentviews/useContentSpec.tsx index bf4bfcea7c..0cee59864c 100644 --- a/web/src/js/__tests__/components/contentviews/useContentSpec.tsx +++ b/web/src/js/__tests__/components/contentviews/useContentSpec.tsx @@ -27,6 +27,6 @@ test("network error", async () => { fetchMock.mockRejectOnce(new Error("I/O error")); render(); await waitFor(() => - screen.getByText("Error getting content: Error: I/O error.") + screen.getByText("Error getting content: Error: I/O error."), ); }); diff --git a/web/src/js/__tests__/components/editors/ValidateEditorSpec.tsx b/web/src/js/__tests__/components/editors/ValidateEditorSpec.tsx index 0caf9c6328..0236aae1fb 100644 --- a/web/src/js/__tests__/components/editors/ValidateEditorSpec.tsx +++ b/web/src/js/__tests__/components/editors/ValidateEditorSpec.tsx @@ -15,7 +15,7 @@ test("ValidateEditor", async () => { content="ok" isValid={(x) => x.includes("ok")} onEditDone={onEditDone} - /> + />, ); expect(asFragment()).toMatchSnapshot(); diff --git a/web/src/js/__tests__/components/editors/ValueEditorSpec.tsx b/web/src/js/__tests__/components/editors/ValueEditorSpec.tsx index 50cfa6e57d..32d2ab498c 100644 --- a/web/src/js/__tests__/components/editors/ValueEditorSpec.tsx +++ b/web/src/js/__tests__/components/editors/ValueEditorSpec.tsx @@ -4,13 +4,13 @@ import { render, waitFor } from "../../test-utils"; test("ValueEditor", async () => { const onEditDone = jest.fn(); - let editor: { current?: ValueEditor | null } = {}; + const editor: { current?: ValueEditor | null } = {}; const { asFragment } = render( (editor.current = x)} content="hello world" onEditDone={onEditDone} - /> + />, ); expect(asFragment()).toMatchSnapshot(); diff --git a/web/src/js/__tests__/components/helpers/AutoScrollSpec.tsx b/web/src/js/__tests__/components/helpers/AutoScrollSpec.tsx index 59b8af462d..3af21025f4 100644 --- a/web/src/js/__tests__/components/helpers/AutoScrollSpec.tsx +++ b/web/src/js/__tests__/components/helpers/AutoScrollSpec.tsx @@ -1,47 +1,56 @@ import * as React from "react"; -import ReactDOM from "react-dom"; -import AutoScroll from "../../../components/helpers/AutoScroll"; -import { calcVScroll } from "../../../components/helpers/VirtualScroll"; -import TestUtils from "react-dom/test-utils"; +import * as autoscroll from "../../../components/helpers/AutoScroll"; +import { fireEvent, render } from "../../test-utils"; describe("Autoscroll", () => { - let mockFn = jest.fn(); - class tComponent extends React.Component { - constructor(props, context) { - super(props, context); - this.state = { vScroll: calcVScroll() }; + interface TComponentProps { + height: number; + } + + class TComponent extends React.Component { + private viewport = React.createRef(); + + getSnapshotBeforeUpdate(prevProps) { + this.fixupJsDom(prevProps.height); + return autoscroll.isAtBottom(this.viewport); } - UNSAFE_componentWillUpdate() { - mockFn("foo"); + componentDidUpdate(prevProps, prevState, snapshot) { + this.fixupJsDom(this.props.height); + if (snapshot) { + autoscroll.adjustScrollTop(this.viewport); + } } - componentDidUpdate() { - mockFn("bar"); + fixupJsDom(scrollHeight: number) { + // work around jsdom limitations + Object.defineProperty(this.viewport.current!, "clientHeight", { + value: 100, + writable: true, + }); + Object.defineProperty(this.viewport.current!, "scrollHeight", { + value: scrollHeight, + writable: true, + }); } render() { - return

foo

; + return
; } } it("should update component", () => { - let Foo = AutoScroll(tComponent), - autoScroll = TestUtils.renderIntoDocument(), - viewport = ReactDOM.findDOMNode(autoScroll); - viewport.scrollTop = 10; - Object.defineProperty(viewport, "scrollHeight", { - value: 10, - writable: true, - }); - autoScroll.UNSAFE_componentWillUpdate(); - expect(mockFn).toBeCalledWith("foo"); - - Object.defineProperty(viewport, "scrollHeight", { - value: 0, - writable: true, - }); - autoScroll.componentDidUpdate(); - expect(mockFn).toBeCalledWith("bar"); + const { rerender, container } = render(); + const viewport = container.firstElementChild!; + + fireEvent.scroll(viewport, { target: { scrollTop: 10 } }); + rerender(); + + expect(viewport.scrollTop).toBe(10); + + fireEvent.scroll(viewport, { target: { scrollTop: 40 } }); + rerender(); + + expect(viewport.scrollTop).toBeGreaterThanOrEqual(60); }); }); diff --git a/web/src/js/__tests__/components/helpers/VirtualScrollSpec.tsx b/web/src/js/__tests__/components/helpers/VirtualScrollSpec.tsx index 605aa32ec0..34d3e35dfa 100644 --- a/web/src/js/__tests__/components/helpers/VirtualScrollSpec.tsx +++ b/web/src/js/__tests__/components/helpers/VirtualScrollSpec.tsx @@ -17,7 +17,7 @@ describe("VirtualScroll", () => { rowHeight: 32, viewportHeight: 400, viewportTop: 0, - }) + }), ).toEqual({ start: 0, end: 0, @@ -34,7 +34,7 @@ describe("VirtualScroll", () => { viewportHeight: 300, viewportTop: 0, rowHeight: 100, - }) + }), ).toEqual({ start: 0, end: 4, @@ -50,7 +50,7 @@ describe("VirtualScroll", () => { rowHeight: 32, viewportHeight: 400, viewportTop: 12_000, - }) + }), ).toEqual({ start: 0, end: 10, @@ -67,7 +67,7 @@ describe("VirtualScroll", () => { viewportHeight: 400, viewportTop: 12_000, rowHeight: 32, - }) + }), ).toEqual({ start: 0, end: 4, diff --git a/web/src/js/__tests__/ducks/_tbackendstate.ts b/web/src/js/__tests__/ducks/_tbackendstate.ts index a847f318d9..2cedb31d61 100644 --- a/web/src/js/__tests__/ducks/_tbackendstate.ts +++ b/web/src/js/__tests__/ducks/_tbackendstate.ts @@ -1,4 +1,4 @@ -/** Auto-generated by test_app.py:test_generate_state_js */ +/** Auto-generated by web/gen/state_js.py */ import {BackendState} from '../../ducks/backendState'; export function TBackendState(): Required { return { @@ -7,8 +7,9 @@ export function TBackendState(): Required { "Auto", "Raw" ], - "servers": [ - { + "platform": "darwin", + "servers": { + "regular": { "description": "HTTP(S) proxy", "full_spec": "regular", "is_running": true, @@ -25,7 +26,7 @@ export function TBackendState(): Required { ], "type": "regular" }, - { + "reverse:example.com": { "description": "reverse proxy to example.com", "full_spec": "reverse:example.com", "is_running": false, @@ -33,7 +34,7 @@ export function TBackendState(): Required { "listen_addrs": [], "type": "reverse" }, - { + "socks5": { "description": "SOCKS v5 proxy", "full_spec": "socks5", "is_running": false, @@ -41,7 +42,7 @@ export function TBackendState(): Required { "listen_addrs": [], "type": "socks5" } - ], + }, "version": "1.2.3" } } diff --git a/web/src/js/__tests__/ducks/_tflow.ts b/web/src/js/__tests__/ducks/_tflow.ts index 025fccdfef..9fc122d9a3 100644 --- a/web/src/js/__tests__/ducks/_tflow.ts +++ b/web/src/js/__tests__/ducks/_tflow.ts @@ -1,4 +1,4 @@ -/** Auto-generated by test_app.py:test_generate_tflow_js */ +/** Auto-generated by web/gen/tflow_js.py */ import {HTTPFlow, TCPFlow, UDPFlow, DNSFlow} from '../../flow'; export function THTTPFlow(): Required { return { diff --git a/web/src/js/__tests__/ducks/commandBarSpec.tsx b/web/src/js/__tests__/ducks/commandBarSpec.tsx index 3480bf5980..04c94e5d42 100644 --- a/web/src/js/__tests__/ducks/commandBarSpec.tsx +++ b/web/src/js/__tests__/ducks/commandBarSpec.tsx @@ -5,7 +5,7 @@ test("CommandBar", async () => { visible: false, }); expect( - reduceCommandBar(undefined, commandBarActions.toggleVisibility()) + reduceCommandBar(undefined, commandBarActions.toggleVisibility()), ).toEqual({ visible: true, }); diff --git a/web/src/js/__tests__/ducks/connectionSpec.tsx b/web/src/js/__tests__/ducks/connectionSpec.tsx index 0254411321..ee90c06c5c 100644 --- a/web/src/js/__tests__/ducks/connectionSpec.tsx +++ b/web/src/js/__tests__/ducks/connectionSpec.tsx @@ -1,5 +1,4 @@ -import reduceConnection from "../../ducks/connection"; -import * as ConnectionActions from "../../ducks/connection"; +import reduceConnection, * as ConnectionActions from "../../ducks/connection"; import { ConnectionState } from "../../ducks/connection"; describe("connection reducer", () => { @@ -12,7 +11,7 @@ describe("connection reducer", () => { it("should handle start fetch", () => { expect( - reduceConnection(undefined, ConnectionActions.startFetching()) + reduceConnection(undefined, ConnectionActions.startFetching()), ).toEqual({ state: ConnectionState.FETCHING, message: undefined, @@ -23,8 +22,8 @@ describe("connection reducer", () => { expect( reduceConnection( undefined, - ConnectionActions.connectionEstablished() - ) + ConnectionActions.connectionEstablished(), + ), ).toEqual({ state: ConnectionState.ESTABLISHED, message: undefined, @@ -35,8 +34,8 @@ describe("connection reducer", () => { expect( reduceConnection( undefined, - ConnectionActions.connectionError("no internet") - ) + ConnectionActions.connectionError("no internet"), + ), ).toEqual({ state: ConnectionState.ERROR, message: "no internet", @@ -45,7 +44,7 @@ describe("connection reducer", () => { it("should handle offline mode", () => { expect( - reduceConnection(undefined, ConnectionActions.setOffline()) + reduceConnection(undefined, ConnectionActions.setOffline()), ).toEqual({ state: ConnectionState.OFFLINE, message: undefined, diff --git a/web/src/js/__tests__/ducks/eventLogSpec.tsx b/web/src/js/__tests__/ducks/eventLogSpec.tsx index 4560f85daf..f2e042f9e3 100644 --- a/web/src/js/__tests__/ducks/eventLogSpec.tsx +++ b/web/src/js/__tests__/ducks/eventLogSpec.tsx @@ -1,4 +1,5 @@ import reduceEventLog, * as eventLogActions from "../../ducks/eventLog"; +import { LogLevel } from "../../ducks/eventLog"; import { reduce } from "../../ducks/utils/store"; describe("event log reducer", () => { @@ -17,9 +18,9 @@ describe("event log reducer", () => { }); it("should be possible to toggle filter", () => { - let state = reduceEventLog(undefined, eventLogActions.add("foo")); + const state = reduceEventLog(undefined, eventLogActions.add("foo")); expect( - reduceEventLog(state, eventLogActions.toggleFilter("info")) + reduceEventLog(state, eventLogActions.toggleFilter(LogLevel.info)), ).toEqual({ visible: false, filters: { ...state.filters, info: false }, @@ -28,9 +29,9 @@ describe("event log reducer", () => { }); it("should be possible to toggle visibility", () => { - let state = reduceEventLog(undefined, {}); + const state = reduceEventLog(undefined, {}); expect( - reduceEventLog(state, eventLogActions.toggleVisibility()) + reduceEventLog(state, eventLogActions.toggleVisibility()), ).toEqual({ visible: true, filters: { ...state.filters }, @@ -39,7 +40,7 @@ describe("event log reducer", () => { }); it("should be possible to add message", () => { - let state = reduceEventLog(undefined, eventLogActions.add("foo")); + const state = reduceEventLog(undefined, eventLogActions.add("foo")); expect(state.visible).toBeFalsy(); expect(state.filters).toEqual({ debug: false, diff --git a/web/src/js/__tests__/ducks/flowsSpec.tsx b/web/src/js/__tests__/ducks/flowsSpec.tsx index 03dc030ef8..79d3e53733 100644 --- a/web/src/js/__tests__/ducks/flowsSpec.tsx +++ b/web/src/js/__tests__/ducks/flowsSpec.tsx @@ -8,14 +8,14 @@ jest.mock("../../utils"); describe("flow reducer", () => { let s; - for (let i of ["1", "2", "3", "4"]) { + for (const i of ["1", "2", "3", "4"]) { s = reduceFlows(s, { type: flowActions.ADD, data: { id: i }, cmd: "add", }); } - let state = s; + const state = s; it("should return initial state", () => { expect(reduceFlows(undefined, {})).toEqual({ @@ -37,7 +37,10 @@ describe("flow reducer", () => { it("should be possible to deselect a flow", () => { expect( - reduceFlows({ ...state, selected: ["1"] }, flowActions.select()) + reduceFlows( + { ...state, selected: ["1"] }, + flowActions.select(), + ), ).toEqual({ ...state, selected: [], @@ -47,12 +50,12 @@ describe("flow reducer", () => { it("should be possible to select relative", () => { // haven't selected any flow expect(flowActions.selectRelative(state, 1)).toEqual( - flowActions.select("4") + flowActions.select("4"), ); // already selected some flows expect( - flowActions.selectRelative({ ...state, selected: [2] }, 1) + flowActions.selectRelative({ ...state, selected: [2] }, 1), ).toEqual(flowActions.select("3")); }); @@ -64,7 +67,7 @@ describe("flow reducer", () => { type: flowActions.REMOVE, data: "2", cmd: "remove", - } + }, ); expect(next.selected).toEqual(["3"]); @@ -75,7 +78,7 @@ describe("flow reducer", () => { type: flowActions.REMOVE, data: "4", cmd: "remove", - } + }, ); expect(next.selected).toEqual(["3"]); @@ -86,44 +89,44 @@ describe("flow reducer", () => { type: flowActions.REMOVE, data: "3", cmd: "remove", - } + }, ); expect(next.selected).toEqual(["2", "4"]); }); }); it("should be possible to set filter", () => { - let filt = "~u 123"; + const filt = "~u 123"; expect( - reduceFlows(undefined, flowActions.setFilter(filt)).filter + reduceFlows(undefined, flowActions.setFilter(filt)).filter, ).toEqual(filt); }); it("should be possible to set highlight", () => { - let key = "foo"; + const key = "foo"; expect( - reduceFlows(undefined, flowActions.setHighlight(key)).highlight + reduceFlows(undefined, flowActions.setHighlight(key)).highlight, ).toEqual(key); }); it("should be possible to set sort", () => { - let sort = { column: "tls", desc: true }; + const sort = { column: "tls", desc: true }; expect( reduceFlows(undefined, flowActions.setSort(sort.column, sort.desc)) - .sort + .sort, ).toEqual(sort); }); }); describe("flows actions", () => { - let store = TStore(); - let tflow = TFlow(); + const store = TStore(); + const tflow = TFlow(); it("should handle resume action", () => { store.dispatch(flowActions.resume(tflow)); expect(fetchApi).toBeCalledWith( "/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/resume", - { method: "POST" } + { method: "POST" }, ); }); @@ -136,7 +139,7 @@ describe("flows actions", () => { store.dispatch(flowActions.kill(tflow)); expect(fetchApi).toBeCalledWith( "/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/kill", - { method: "POST" } + { method: "POST" }, ); }); @@ -149,7 +152,7 @@ describe("flows actions", () => { store.dispatch(flowActions.remove(tflow)); expect(fetchApi).toBeCalledWith( "/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29", - { method: "DELETE" } + { method: "DELETE" }, ); }); @@ -157,7 +160,7 @@ describe("flows actions", () => { store.dispatch(flowActions.duplicate(tflow)); expect(fetchApi).toBeCalledWith( "/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/duplicate", - { method: "POST" } + { method: "POST" }, ); }); @@ -165,7 +168,7 @@ describe("flows actions", () => { store.dispatch(flowActions.replay(tflow)); expect(fetchApi).toBeCalledWith( "/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/replay", - { method: "POST" } + { method: "POST" }, ); }); @@ -173,7 +176,7 @@ describe("flows actions", () => { store.dispatch(flowActions.revert(tflow)); expect(fetchApi).toBeCalledWith( "/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/revert", - { method: "POST" } + { method: "POST" }, ); }); @@ -181,13 +184,13 @@ describe("flows actions", () => { store.dispatch(flowActions.update(tflow, "foo")); expect(fetchApi.put).toBeCalledWith( "/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29", - "foo" + "foo", ); }); it("should handle uploadContent action", () => { - let body = new FormData(), - file = new window.Blob(["foo"], { type: "plain/text" }); + const body = new FormData(); + const file = new window.Blob(["foo"], { type: "plain/text" }); body.append("file", file); store.dispatch(flowActions.uploadContent(tflow, "foo", "foo")); // window.Blob's lastModified is always the current time, @@ -197,7 +200,7 @@ describe("flows actions", () => { { method: "POST", body: expect.anything(), - } + }, ); }); @@ -207,7 +210,7 @@ describe("flows actions", () => { }); it("should handle upload action", () => { - let body = new FormData(); + const body = new FormData(); body.append("file", "foo"); store.dispatch(flowActions.upload("foo")); expect(fetchApi).toBeCalledWith("/flows/dump", { @@ -218,8 +221,8 @@ describe("flows actions", () => { }); test("makeSort", () => { - const a = TFlow(), - b = TFlow(); + const a = TFlow(); + const b = TFlow(); a.request.scheme = "https"; a.request.method = "POST"; a.request.path = "/foo"; @@ -227,7 +230,7 @@ test("makeSort", () => { a.response.status_code = 418; Object.keys(FlowColumns).forEach((column, i) => { - // @ts-ignore + // @ts-expect-error jest is funky about type annotations here. const sort = flowActions.makeSort({ column, desc: i % 2 == 0 }); expect(sort(a, b)).toBeDefined(); }); diff --git a/web/src/js/__tests__/ducks/indexSpec.tsx b/web/src/js/__tests__/ducks/indexSpec.tsx deleted file mode 100644 index c72900fbaa..0000000000 --- a/web/src/js/__tests__/ducks/indexSpec.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { rootReducer } from "../../ducks/index"; - -describe("reduceState in js/ducks/index.js", () => { - it("should combine flow and header", () => { - let state = rootReducer(undefined, { type: "other" }); - expect(state.hasOwnProperty("eventLog")).toBeTruthy(); - expect(state.hasOwnProperty("flows")).toBeTruthy(); - expect(state.hasOwnProperty("connection")).toBeTruthy(); - expect(state.hasOwnProperty("ui")).toBeTruthy(); - }); -}); diff --git a/web/src/js/__tests__/ducks/modes/dnsSpec.tsx b/web/src/js/__tests__/ducks/modes/dnsSpec.tsx new file mode 100644 index 0000000000..690b3d8dad --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/dnsSpec.tsx @@ -0,0 +1,116 @@ +import dnsReducer, { + initialState, + setListenHost, + setListenPort, + setActive, +} from "./../../../ducks/modes/dns"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("dnsSlice", () => { + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.dns[0]).toEqual({ + active: false, + }); + + const server = store.getState().modes.dns[0]; + await store.dispatch(setActive({ value: true, server })); + await store.dispatch(setListenHost({ value: "127.0.0.1", server })); + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(store.getState().modes.dns[0]).toEqual({ + active: true, + listen_host: "127.0.0.1", + listen_port: 4444, + }); + + expect(fetchMock).toHaveBeenCalledTimes(3); + }); + + it("should handle error when setting dns mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.dns[0]; + await store.dispatch(setActive({ value: false, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.dns[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen port", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.dns[0]; + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.dns[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen host", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.dns[0]; + await store.dispatch(setListenHost({ value: "localhost", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.dns[0].error).toBe("invalid spec"); + }); + + it("should handle RECEIVE_STATE with an active dns proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "dns@localhost:8081": { + description: "HTTP(S) proxy", + full_spec: "dns@localhost:8081", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8081], + ["::1", 8081], + ], + type: "dns", + }, + }, + }, + } as PayloadAction>; + const newState = dnsReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + listen_host: "localhost", + listen_port: 8081, + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active dns proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = dnsReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + ui_id: newState[0].ui_id, + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/localSpec.tsx b/web/src/js/__tests__/ducks/modes/localSpec.tsx new file mode 100644 index 0000000000..bfaa1bbf7d --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/localSpec.tsx @@ -0,0 +1,105 @@ +import localReducer, { + initialState, + setActive, + setSelectedProcesses, +} from "../../../ducks/modes/local"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("localSlice", () => { + beforeEach(() => { + enableFetchMocks(); + fetchMock.resetMocks(); + }); + + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.local[0]).toEqual({ + active: false, + selectedProcesses: "", + }); + + const server = store.getState().modes.local[0]; + await store.dispatch(setActive({ value: true, server })); + await store.dispatch(setSelectedProcesses({ value: "curl", server })); + + expect(store.getState().modes.local[0]).toEqual({ + active: true, + selectedProcesses: "curl", + }); + + expect(fetchMock).toHaveBeenCalledTimes(2); + }); + + it("should handle error when setting local mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.local[0]; + await store.dispatch(setActive({ value: true, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.local[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting processes", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.local[0]; + await store.dispatch(setSelectedProcesses({ value: "curl", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.local[0].error).toBe("invalid spec"); + }); + + it("should handle RECEIVE_STATE with an active local proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "local:curl": { + description: "Local redirector", + full_spec: "local:curl", + is_running: true, + last_exception: null, + listen_addrs: [], + type: "local", + }, + }, + }, + } as PayloadAction>; + const newState = localReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + selectedProcesses: "curl", + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active local proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = localReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + selectedProcesses: "", + ui_id: newState[0].ui_id, + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/regularSpec.tsx b/web/src/js/__tests__/ducks/modes/regularSpec.tsx new file mode 100644 index 0000000000..e786a3fb3c --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/regularSpec.tsx @@ -0,0 +1,116 @@ +import regularReducer, { + initialState, + setListenHost, + setListenPort, + setActive, +} from "./../../../ducks/modes/regular"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("regularSlice", () => { + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.regular[0]).toEqual({ + active: true, + }); + + const server = store.getState().modes.regular[0]; + await store.dispatch(setActive({ value: false, server })); + await store.dispatch(setListenHost({ value: "127.0.0.1", server })); + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(store.getState().modes.regular[0]).toEqual({ + active: false, + listen_host: "127.0.0.1", + listen_port: 4444, + }); + + expect(fetchMock).toHaveBeenCalledTimes(3); + }); + + it("should handle error when setting regular mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.regular[0]; + await store.dispatch(setActive({ value: false, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.regular[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen port", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.regular[0]; + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.regular[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen host", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.regular[0]; + await store.dispatch(setListenHost({ value: "localhost", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.regular[0].error).toBe("invalid spec"); + }); + + it("should handle RECEIVE_STATE with an active regular proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "regular@localhost:8081": { + description: "HTTP(S) proxy", + full_spec: "regular@localhost:8081", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8081], + ["::1", 8081], + ], + type: "regular", + }, + }, + }, + } as PayloadAction>; + const newState = regularReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + listen_host: "localhost", + listen_port: 8081, + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active regular proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = regularReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + ui_id: newState[0].ui_id, + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/reverseSpec.tsx b/web/src/js/__tests__/ducks/modes/reverseSpec.tsx new file mode 100644 index 0000000000..fb19e908f4 --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/reverseSpec.tsx @@ -0,0 +1,224 @@ +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import reverseReducer, { + initialState, + setDestination, + setProtocol, + setActive, + setListenHost, + setListenPort, + addServer, + removeServer, +} from "../../../ducks/modes/reverse"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import { ReverseProxyProtocols } from "../../../backends/consts"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("reverseSlice", () => { + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.reverse[0]).toEqual({ + active: false, + protocol: ReverseProxyProtocols.HTTPS, + destination: "example.com", + }); + + const firstServer = store.getState().modes.reverse[0]; + await store.dispatch(setActive({ value: true, server: firstServer })); + await store.dispatch( + setListenHost({ value: "127.0.0.1", server: firstServer }), + ); + await store.dispatch( + setListenPort({ value: 4444, server: firstServer }), + ); + await store.dispatch( + setProtocol({ + value: ReverseProxyProtocols.HTTPS, + server: firstServer, + }), + ); + await store.dispatch( + setDestination({ value: "example.com:8085", server: firstServer }), + ); + + expect(store.getState().modes.reverse[0]).toEqual({ + active: true, + listen_host: "127.0.0.1", + listen_port: 4444, + protocol: ReverseProxyProtocols.HTTPS, + destination: "example.com:8085", + }); + + expect(fetchMock).toHaveBeenCalledTimes(5); + }); + + it("should handle error when setting reverse mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.reverse[0]; + await store.dispatch(setActive({ value: true, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.reverse[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen port", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.reverse[0]; + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.reverse[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen host", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.reverse[0]; + await store.dispatch(setListenHost({ value: "localhost", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.reverse[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting destination", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.reverse[0]; + await store.dispatch(setDestination({ value: "example.com", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.reverse[0].error).toBe("invalid spec"); + }); + + it("should handle the addition of a new default reverse server", async () => { + enableFetchMocks(); + + const store = TStore(); + + expect(store.getState().modes.reverse.length).toBe(2); + + await store.dispatch(addServer()); + + expect(store.getState().modes.reverse.length).toBe(3); + expect(store.getState().modes.reverse[2]).toEqual({ + active: false, + protocol: ReverseProxyProtocols.HTTPS, + destination: "", + ui_id: store.getState().modes.reverse[2].ui_id, + }); + }); + + it("should handle the deletion of an active reverse server", async () => { + enableFetchMocks(); + + const store = TStore(); + + expect(store.getState().modes.reverse.length).toBe(2); + + const firstServer = store.getState().modes.reverse[0]; + await store.dispatch(setActive({ value: true, server: firstServer })); + + const consoleSpy = jest.spyOn(console, "error"); + await store.dispatch(removeServer(store.getState().modes.reverse[0])); + + expect(store.getState().modes.reverse.length).toBe(1); + expect(consoleSpy).toHaveBeenCalledWith( + "servers should be deactivated before removal", + ); + consoleSpy.mockRestore(); + }); + + it("should handle RECEIVE_STATE with an active reverse proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "reverse:tls://example.com:8085@localhost:8080": { + description: "reverse proxy to tls://example.com:8085", + full_spec: + "reverse:tls://example.com:8085@localhost:8080", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8080], + ["::1", 8080, 0, 0], + ], + type: "reverse", + }, + }, + }, + } as PayloadAction>; + const newState = reverseReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + protocol: ReverseProxyProtocols.TLS, + destination: "example.com:8085", + listen_host: "localhost", + listen_port: 8080, + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active reverse proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = reverseReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + ui_id: newState[0].ui_id, + destination: "", + protocol: ReverseProxyProtocols.HTTPS, + }, + ]); + }); + + it("should handle RECEIVE_STATE with an active reverse proxy and set protocol to HTTPS if destination is missing", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "reverse:example.com:8085@localhost:8080": { + description: "reverse proxy to example.com:8085", + full_spec: "reverse:example.com:8085@localhost:8080", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8080], + ["::1", 8080, 0, 0], + ], + type: "reverse", + }, + }, + }, + } as PayloadAction>; + const newState = reverseReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + protocol: ReverseProxyProtocols.HTTPS, + destination: "example.com:8085", + listen_host: "localhost", + listen_port: 8080, + ui_id: newState[0].ui_id, + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/socksSpec.tsx b/web/src/js/__tests__/ducks/modes/socksSpec.tsx new file mode 100644 index 0000000000..dda061c0b5 --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/socksSpec.tsx @@ -0,0 +1,116 @@ +import socksReducer, { + initialState, + setListenHost, + setListenPort, + setActive, +} from "./../../../ducks/modes/socks"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("socksSlice", () => { + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.socks[0]).toEqual({ + active: false, + }); + + const server = store.getState().modes.socks[0]; + await store.dispatch(setActive({ value: true, server })); + await store.dispatch(setListenHost({ value: "127.0.0.1", server })); + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(store.getState().modes.socks[0]).toEqual({ + active: true, + listen_host: "127.0.0.1", + listen_port: 4444, + }); + + expect(fetchMock).toHaveBeenCalledTimes(3); + }); + + it("should handle error when setting socks mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.socks[0]; + await store.dispatch(setActive({ value: false, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.socks[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen port", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.socks[0]; + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.socks[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen host", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.socks[0]; + await store.dispatch(setListenHost({ value: "localhost", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.socks[0].error).toBe("invalid spec"); + }); + + it("should handle RECEIVE_STATE with an active socks proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "socks5@localhost:8081": { + description: "SOCKS v5 proxy", + full_spec: "socks5@localhost:8081", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8081], + ["::1", 8081], + ], + type: "socks5", + }, + }, + }, + } as PayloadAction>; + const newState = socksReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + listen_host: "localhost", + listen_port: 8081, + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active socks proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = socksReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + ui_id: newState[0].ui_id, + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/transparentSpec.tsx b/web/src/js/__tests__/ducks/modes/transparentSpec.tsx new file mode 100644 index 0000000000..d2b3c701ce --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/transparentSpec.tsx @@ -0,0 +1,122 @@ +import transparentReducer, { + initialState, + setListenHost, + setListenPort, + setActive, +} from "./../../../ducks/modes/transparent"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("transparentSlice", () => { + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.transparent[0]).toEqual({ + active: false, + }); + + const server = store.getState().modes.transparent[0]; + await store.dispatch(setActive({ value: true, server })); + await store.dispatch(setListenHost({ value: "127.0.0.1", server })); + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(store.getState().modes.transparent[0]).toEqual({ + active: true, + listen_host: "127.0.0.1", + listen_port: 4444, + }); + + expect(fetchMock).toHaveBeenCalledTimes(3); + }); + + it("should handle error when setting transparent mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.transparent[0]; + await store.dispatch(setActive({ value: false, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.transparent[0].error).toBe( + "invalid spec", + ); + }); + + it("should handle error when setting listen port", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.transparent[0]; + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.transparent[0].error).toBe( + "invalid spec", + ); + }); + + it("should handle error when setting listen host", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.transparent[0]; + await store.dispatch(setListenHost({ value: "localhost", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.transparent[0].error).toBe( + "invalid spec", + ); + }); + + it("should handle RECEIVE_STATE with an active transparent proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "transparent@localhost:8081": { + description: "Transparent Proxy", + full_spec: "transparent@localhost:8081", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8081], + ["::1", 8081], + ], + type: "transparent", + }, + }, + }, + } as PayloadAction>; + const newState = transparentReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + listen_host: "localhost", + listen_port: 8081, + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active transparent proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = transparentReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + ui_id: newState[0].ui_id, + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/upstreamSpec.tsx b/web/src/js/__tests__/ducks/modes/upstreamSpec.tsx new file mode 100644 index 0000000000..daab98690d --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/upstreamSpec.tsx @@ -0,0 +1,153 @@ +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import upstreamReducer, { + initialState, + setDestination, + setActive, + setListenHost, + setListenPort, +} from "../../../ducks/modes/upstream"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("upstreamSlice", () => { + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.upstream[0]).toEqual({ + active: false, + destination: "example.com", + }); + + await store.dispatch( + setActive({ + value: true, + server: store.getState().modes.upstream[0], + }), + ); + await store.dispatch( + setListenHost({ + value: "127.0.0.1", + server: store.getState().modes.upstream[0], + }), + ); + await store.dispatch( + setListenPort({ + value: 4444, + server: store.getState().modes.upstream[0], + }), + ); + await store.dispatch( + setDestination({ + value: "example.com:8085", + server: store.getState().modes.upstream[0], + }), + ); + + expect(store.getState().modes.upstream[0]).toEqual({ + active: true, + listen_host: "127.0.0.1", + listen_port: 4444, + destination: "example.com:8085", + }); + + expect(fetchMock).toHaveBeenCalledTimes(4); + }); + + it("should handle error when setting upstream mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.upstream[0]; + await store.dispatch(setActive({ value: true, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.upstream[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen port", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.upstream[0]; + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.upstream[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen host", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.upstream[0]; + await store.dispatch(setListenHost({ value: "localhost", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.upstream[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting destination", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.upstream[0]; + await store.dispatch(setDestination({ value: "example.com", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.upstream[0].error).toBe("invalid spec"); + }); + + it("should handle RECEIVE_STATE with an active upstream proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "upstream:https://example.com:8085@localhost:8080": { + description: "HTTP(S) proxy (upstream mode)", + full_spec: + "upstream:https://example.com:8085@localhost:8080", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8080], + ["::1", 8080, 0, 0], + ], + type: "upstream", + }, + }, + }, + } as PayloadAction>; + const newState = upstreamReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + destination: "https://example.com:8085", + listen_host: "localhost", + listen_port: 8080, + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active upstream proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = upstreamReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + ui_id: newState[0].ui_id, + destination: "", + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/utilsSpec.tsx b/web/src/js/__tests__/ducks/modes/utilsSpec.tsx new file mode 100644 index 0000000000..f02df1fef5 --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/utilsSpec.tsx @@ -0,0 +1,53 @@ +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { TStore } from "../tutils"; +import { isActiveMode, updateModes } from "../../../ducks/modes/utils"; + +enableFetchMocks(); + +describe("updateMode action creator", () => { + beforeEach(() => { + fetchMock.resetMocks(); + }); + + it("should call updateMode method with a successful api call", async () => { + const store = TStore(); + fetchMock.mockResponseOnce(JSON.stringify({ success: true })); + + await store.dispatch(() => updateModes(null, store)); + + const expectedUrl = "./options"; + const expectedBody = JSON.stringify({ mode: ["regular"] }); + + const actualCall = fetchMock.mock.calls[0]; + const actualUrl = actualCall[0]; + const actualBody = actualCall[1]?.body; + + expect(actualUrl).toEqual(expectedUrl); + expect(actualBody).toEqual(expectedBody); + }); + + it("fetch HTTP status != 200 throws", async () => { + const store = TStore(); + fetchMock.mockResponseOnce("invalid query", { status: 400 }); + await expect( + store.dispatch(() => updateModes(null, store)), + ).rejects.toThrow("invalid query"); + }); + + it("fetch error throws", async () => { + const store = TStore(); + fetchMock.mockRejectOnce(new Error("network error")); + await expect( + store.dispatch(() => updateModes(null, store)), + ).rejects.toThrow("network error"); + }); +}); + +describe("isActiveMode", () => { + it("should work", () => { + expect(isActiveMode({ active: false })).toBe(false); + expect(isActiveMode({ active: true })).toBe(true); + expect(isActiveMode({ active: true, error: "failed" })).toBe(false); + expect(isActiveMode({ active: false, error: "failed" })).toBe(false); + }); +}); diff --git a/web/src/js/__tests__/ducks/modes/wireguardSpec.tsx b/web/src/js/__tests__/ducks/modes/wireguardSpec.tsx new file mode 100644 index 0000000000..da19b7a6f7 --- /dev/null +++ b/web/src/js/__tests__/ducks/modes/wireguardSpec.tsx @@ -0,0 +1,131 @@ +import wireguardReducer, { + initialState, + setListenHost, + setListenPort, + setActive, + setFilePath, +} from "./../../../ducks/modes/wireguard"; +import { + RECEIVE as STATE_RECEIVE, + BackendState, +} from "../../../ducks/backendState"; +import { TStore } from "../tutils"; +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { PayloadAction } from "@reduxjs/toolkit"; + +describe("wireguardSlice", () => { + it("should have working setters", async () => { + enableFetchMocks(); + const store = TStore(); + + expect(store.getState().modes.wireguard[0]).toEqual({ + active: false, + }); + + const server = store.getState().modes.wireguard[0]; + await store.dispatch(setActive({ value: false, server })); + await store.dispatch(setListenHost({ value: "127.0.0.1", server })); + await store.dispatch(setListenPort({ value: 4444, server })); + await store.dispatch(setFilePath({ value: "/path/example", server })); + + expect(store.getState().modes.wireguard[0]).toEqual({ + active: false, + listen_host: "127.0.0.1", + listen_port: 4444, + file_path: "/path/example", + }); + + expect(fetchMock).toHaveBeenCalledTimes(4); + }); + + it("should handle error when setting wireguard mode", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.wireguard[0]; + await store.dispatch(setActive({ value: true, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.wireguard[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen port", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.wireguard[0]; + await store.dispatch(setListenPort({ value: 4444, server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.wireguard[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting listen host", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.wireguard[0]; + await store.dispatch(setListenHost({ value: "localhost", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.wireguard[0].error).toBe("invalid spec"); + }); + + it("should handle error when setting file path", async () => { + fetchMock.mockReject(new Error("invalid spec")); + const store = TStore(); + + const server = store.getState().modes.wireguard[0]; + await store.dispatch(setFilePath({ value: "/path/example", server })); + + expect(fetchMock).toHaveBeenCalled(); + expect(store.getState().modes.wireguard[0].error).toBe("invalid spec"); + }); + + it("should handle RECEIVE_STATE with an active wireguard proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: { + "wireguard:/path/example@localhost:8081": { + description: "WireGuard server", + full_spec: "wireguard:/path/example@localhost:8081", + is_running: true, + last_exception: null, + listen_addrs: [ + ["127.0.0.1", 8081], + ["::1", 8081], + ], + type: "wireguard", + }, + }, + }, + } as PayloadAction>; + const newState = wireguardReducer(initialState, action); + expect(newState).toEqual([ + { + active: true, + listen_host: "localhost", + listen_port: 8081, + file_path: "/path/example", + ui_id: newState[0].ui_id, + }, + ]); + }); + + it("should handle RECEIVE_STATE with no active wireguard proxy", () => { + const action = { + type: STATE_RECEIVE.type, + payload: { + servers: {}, + }, + } as PayloadAction>; + const newState = wireguardReducer(initialState, action); + expect(newState).toEqual([ + { + active: false, + ui_id: newState[0].ui_id, + }, + ]); + }); +}); diff --git a/web/src/js/__tests__/ducks/optionsSpec.tsx b/web/src/js/__tests__/ducks/optionsSpec.tsx index b0e71b25ae..9b5d695585 100644 --- a/web/src/js/__tests__/ducks/optionsSpec.tsx +++ b/web/src/js/__tests__/ducks/optionsSpec.tsx @@ -1,79 +1,81 @@ -import reduceOptions, * as OptionsActions from "../../ducks/options"; -import * as OptionsEditorActions from "../../ducks/ui/optionsEditor"; +import reduceOptions, * as optionsActions from "../../ducks/options"; import { enableFetchMocks } from "jest-fetch-mock"; import { TStore } from "./tutils"; +import { waitFor } from "@testing-library/dom"; + +enableFetchMocks(); describe("option reducer", () => { it("should return initial state", () => { expect(reduceOptions(undefined, { type: "other" })).toEqual( - OptionsActions.defaultState + optionsActions.defaultState, ); }); it("should handle receive action", () => { - let action = { - type: OptionsActions.RECEIVE, + const action = { + type: optionsActions.RECEIVE, data: { id: { value: "foo" } }, }; expect(reduceOptions(undefined, action)).toEqual({ id: "foo" }); }); it("should handle update action", () => { - let action = { - type: OptionsActions.UPDATE, + const action = { + type: optionsActions.UPDATE, data: { id: { value: 1 } }, }; expect(reduceOptions(undefined, action)).toEqual({ - ...OptionsActions.defaultState, + ...optionsActions.defaultState, id: 1, }); }); }); test("sendUpdate", async () => { - enableFetchMocks(); - let store = TStore(); + const store = TStore(); fetchMock.mockResponseOnce("fooerror", { status: 404 }); - await store.dispatch((dispatch) => - OptionsActions.pureSendUpdate("intercept", "~~~", dispatch) + await store.dispatch(optionsActions.update("intercept", "~~~")); + await waitFor(() => + expect(store.getState().ui.optionsEditor.intercept).toEqual({ + error: "fooerror", + isUpdating: false, + value: "~~~", + }), ); - expect(store.getActions()).toEqual([ - OptionsEditorActions.updateError("intercept", "fooerror"), - ]); - store.clearActions(); fetchMock.mockResponseOnce("", { status: 200 }); - await store.dispatch((dispatch) => - OptionsActions.pureSendUpdate("intercept", "valid", dispatch) + await store.dispatch(optionsActions.update("intercept", "valid")); + await waitFor(() => + expect(store.getState().ui.optionsEditor.intercept).toBeUndefined(), ); - expect(store.getActions()).toEqual([ - OptionsEditorActions.updateSuccess("intercept"), - ]); }); test("save", async () => { - enableFetchMocks(); fetchMock.mockResponseOnce(""); - let store = TStore(); - await store.dispatch(OptionsActions.save()); + const store = TStore(); + await store.dispatch(optionsActions.save()); expect(fetchMock).toBeCalled(); }); test("addInterceptFilter", async () => { - enableFetchMocks(); fetchMock.mockClear(); fetchMock.mockResponses("", ""); - let store = TStore(); - await store.dispatch(OptionsActions.addInterceptFilter("~u foo")); + const store = TStore(); + await store.dispatch(optionsActions.addInterceptFilter("~u foo")); expect(fetchMock.mock.calls[0][1]?.body).toEqual('{"intercept":"~u foo"}'); - store.getState().options.intercept = "~u foo"; - await store.dispatch(OptionsActions.addInterceptFilter("~u foo")); + store.dispatch({ + type: optionsActions.UPDATE, + data: { intercept: { value: "~u foo" } }, + }); + + await store.dispatch(optionsActions.addInterceptFilter("~u foo")); expect(fetchMock.mock.calls).toHaveLength(1); - await store.dispatch(OptionsActions.addInterceptFilter("~u bar")); + await store.dispatch(optionsActions.addInterceptFilter("~u bar")); expect(fetchMock.mock.calls[1][1]?.body).toEqual( - '{"intercept":"~u foo | ~u bar"}' + '{"intercept":"~u foo | ~u bar"}', ); }); diff --git a/web/src/js/__tests__/ducks/options_metaSpec.tsx b/web/src/js/__tests__/ducks/options_metaSpec.tsx index 82d1933862..39ff3a80e6 100644 --- a/web/src/js/__tests__/ducks/options_metaSpec.tsx +++ b/web/src/js/__tests__/ducks/options_metaSpec.tsx @@ -3,20 +3,20 @@ import * as OptionsActions from "../../ducks/options"; test("options_meta", async () => { expect(reduceOptionsMeta(undefined, { type: "other" })).toEqual( - OptionsMetaActions.defaultState + OptionsMetaActions.defaultState, ); expect( reduceOptionsMeta(undefined, { type: OptionsActions.RECEIVE, data: { id: { value: "foo" } }, - }) + }), ).toEqual({ id: { value: "foo" } }); expect( reduceOptionsMeta(undefined, { type: OptionsActions.UPDATE, data: { id: { value: 1 } }, - }) + }), ).toEqual({ ...OptionsMetaActions.defaultState, id: { value: 1 } }); }); diff --git a/web/src/js/__tests__/ducks/processesSpec.tsx b/web/src/js/__tests__/ducks/processesSpec.tsx new file mode 100644 index 0000000000..05c79b76d9 --- /dev/null +++ b/web/src/js/__tests__/ducks/processesSpec.tsx @@ -0,0 +1,65 @@ +import fetchMock, { enableFetchMocks } from "jest-fetch-mock"; +import { TStore } from "./tutils"; +import { fetchProcesses } from "../../ducks/processes"; + +describe("processesSlice", () => { + beforeEach(() => { + enableFetchMocks(); + fetchMock.resetMocks(); + }); + + it("should handle fetchProcesses pending state", async () => { + fetchMock.mockResponseOnce(() => new Promise(() => {})); + + const store = TStore(); + + store.dispatch(fetchProcesses()); + expect(store.getState().processes.isLoading).toBe(true); + }); + + it("should handle fetchProcesses fulfilled state", async () => { + const mockProcesses = [ + { + is_visible: true, + executable: "curl.exe", + is_system: "false", + display_name: "curl", + }, + { + is_visible: true, + executable: "http.exe", + is_system: "false", + display_name: "http", + }, + ]; + + fetchMock.mockResponseOnce(JSON.stringify(mockProcesses)); + + const store = TStore(); + + await store.dispatch(fetchProcesses()); + + expect(store.getState().processes.isLoading).toBe(false); + expect(store.getState().processes.currentProcesses).toEqual( + mockProcesses, + ); + expect(fetchMock).toHaveBeenCalledWith("./processes", { + credentials: "same-origin", + }); + }); + + it("should handle fetchProcesses rejected state", async () => { + fetchMock.mockReject(new Error("Failed to fetch processes")); + const store = TStore(); + + await store.dispatch(fetchProcesses()); + + expect(store.getState().processes.isLoading).toBe(false); + expect(store.getState().processes.error).toBe( + "Failed to fetch processes", + ); + expect(fetchMock).toHaveBeenCalledWith("./processes", { + credentials: "same-origin", + }); + }); +}); diff --git a/web/src/js/__tests__/ducks/tutils.ts b/web/src/js/__tests__/ducks/tutils.ts index 868f236075..8bbd1d3305 100644 --- a/web/src/js/__tests__/ducks/tutils.ts +++ b/web/src/js/__tests__/ducks/tutils.ts @@ -1,17 +1,15 @@ -import thunk from "redux-thunk"; -import configureStore, { - MockStoreCreator, - MockStoreEnhanced, -} from "redux-mock-store"; import { ConnectionState } from "../../ducks/connection"; import { TDNSFlow, THTTPFlow, TTCPFlow, TUDPFlow } from "./_tflow"; -import { AppDispatch, RootState } from "../../ducks"; +import { RootState } from "../../ducks"; +import { reducer } from "../../ducks/store"; import { DNSFlow, HTTPFlow, TCPFlow, UDPFlow } from "../../flow"; import { defaultState as defaultOptions } from "../../ducks/options"; import { TBackendState } from "./_tbackendstate"; - -const mockStoreCreator: MockStoreCreator = - configureStore([thunk]); +import { configureStore } from "@reduxjs/toolkit"; +import { Tab } from "../../ducks/ui/tabs"; +import { LogLevel } from "../../ducks/eventLog"; +import { ReverseProxyProtocols } from "../../backends/consts"; +import { defaultReverseState } from "../../modes/reverse"; export { THTTPFlow as TFlow, TTCPFlow, TUDPFlow }; @@ -66,10 +64,16 @@ export const testState: RootState = { activeModal: undefined, }, optionsEditor: { - booleanOption: { isUpdating: true, error: false }, - strOption: { error: true }, - intOption: {}, - choiceOption: {}, + anticache: { isUpdating: true, error: false, value: true }, + cert_passphrase: { + isUpdating: false, + error: "incorrect password", + value: "correcthorsebatterystaple", + }, + }, + tabs: { + current: Tab.Capture, + isInitial: true, }, }, options: defaultOptions, @@ -117,8 +121,8 @@ export const testState: RootState = { error: true, }, view: [ - { id: "1", level: "info", message: "foo" }, - { id: "2", level: "error", message: "bar" }, + { id: "1", level: LogLevel.info, message: "foo" }, + { id: "2", level: LogLevel.error, message: "bar" }, ], byId: {}, // TODO: incomplete list: [], // TODO: incomplete @@ -128,8 +132,79 @@ export const testState: RootState = { commandBar: { visible: false, }, + modes: { + regular: [ + { + active: true, + }, + ], + local: [ + { + active: false, + selectedProcesses: "", + }, + ], + wireguard: [ + { + active: false, + }, + ], + reverse: [ + { + active: false, + protocol: ReverseProxyProtocols.HTTPS, + destination: "example.com", + }, + defaultReverseState(), + ], + transparent: [ + { + active: false, + }, + ], + socks: [ + { + active: false, + }, + ], + upstream: [ + { + active: false, + destination: "example.com", + }, + ], + dns: [ + { + active: false, + }, + ], + }, + processes: { + currentProcesses: [ + { + is_visible: true, + executable: "curl.exe", + is_system: false, + display_name: "curl", + }, + { + is_visible: true, + executable: "http.exe", + is_system: false, + display_name: "http", + }, + ], + isLoading: false, + }, }; -export function TStore(): MockStoreEnhanced { - return mockStoreCreator(testState); -} +export const TStore = () => + configureStore({ + reducer, + preloadedState: testState, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + immutableCheck: { warnAfter: 500_000 }, + serializableCheck: { warnAfter: 500_000 }, + }), + }); diff --git a/web/src/js/__tests__/ducks/ui/flowSpec.tsx b/web/src/js/__tests__/ducks/ui/flowSpec.tsx index ad397004f6..e932177918 100644 --- a/web/src/js/__tests__/ducks/ui/flowSpec.tsx +++ b/web/src/js/__tests__/ducks/ui/flowSpec.tsx @@ -3,20 +3,20 @@ import reduceFlow, * as FlowActions from "../../../ducks/ui/flow"; describe("option reducer", () => { it("should return initial state", () => { expect(reduceFlow(undefined, { type: "other" })).toEqual( - FlowActions.defaultState + FlowActions.defaultState, ); }); it("should handle set tab", () => { expect( - reduceFlow(undefined, FlowActions.selectTab("response")).tab + reduceFlow(undefined, FlowActions.selectTab("response")).tab, ).toEqual("response"); }); it("should handle set content view", () => { expect( reduceFlow(undefined, FlowActions.setContentViewFor("foo", "Raw")) - .contentViewFor["foo"] + .contentViewFor["foo"], ).toEqual("Raw"); }); }); diff --git a/web/src/js/__tests__/ducks/ui/indexSpec.tsx b/web/src/js/__tests__/ducks/ui/indexSpec.tsx index 3db54fe7b3..e04e741552 100644 --- a/web/src/js/__tests__/ducks/ui/indexSpec.tsx +++ b/web/src/js/__tests__/ducks/ui/indexSpec.tsx @@ -2,7 +2,9 @@ import reduceUI from "../../../ducks/ui/index"; describe("reduceUI in js/ducks/ui/index.js", () => { it("should combine flow and header", () => { - let state = reduceUI(undefined, { type: "other" }); - expect(state.hasOwnProperty("flow")).toBeTruthy(); + const state = reduceUI(undefined, { type: "other" }); + expect( + Object.prototype.hasOwnProperty.call(state, "flow"), + ).toBeTruthy(); }); }); diff --git a/web/src/js/__tests__/ducks/ui/keyboardSpec.tsx b/web/src/js/__tests__/ducks/ui/keyboardSpec.tsx index b1803ee9a0..b7070a8684 100644 --- a/web/src/js/__tests__/ducks/ui/keyboardSpec.tsx +++ b/web/src/js/__tests__/ducks/ui/keyboardSpec.tsx @@ -1,6 +1,5 @@ -import reduceFlows, * as flowsActions from "../../../ducks/flows"; +import * as flowsActions from "../../../ducks/flows"; import { onKeyDown } from "../../../ducks/ui/keyboard"; -import * as UIActions from "../../../ducks/ui/flow"; import * as modalActions from "../../../ducks/ui/modal"; import { fetchApi, runCommand } from "../../../utils"; import { TStore } from "../tutils"; @@ -8,198 +7,192 @@ import { TStore } from "../tutils"; jest.mock("../../../utils"); describe("onKeyDown", () => { - let flows = flowsActions.defaultState; - for (let i = 1; i <= 12; i++) { - flows = reduceFlows(flows, { - type: flowsActions.ADD, - data: { id: i + "", request: true, response: true, type: "http" }, - cmd: "add", + const makeStore = () => { + const store = TStore(); + store.dispatch({ + type: flowsActions.RECEIVE, + cmd: "receive", + data: [], }); - } - - const store = TStore(); - store.getState().flows = flows; + store.dispatch(flowsActions.setFilter("")); + store.dispatch(flowsActions.select("1")); + for (let i = 1; i <= 12; i++) { + store.dispatch({ + type: flowsActions.ADD, + cmd: "add", + data: { + id: i + "", + request: true, + response: true, + type: "http", + intercepted: true, + modified: true, + }, + }); + } + return store; + }; - let createKeyEvent = (key, ctrlKey = false) => { - // @ts-ignore + const createKeyEvent = (key, ctrlKey = false) => { + // @ts-expect-error not a real KeyboardEvent return onKeyDown({ key, ctrlKey, preventDefault: jest.fn() }); }; afterEach(() => { - store.clearActions(); - // @ts-ignore + // @ts-expect-error mocking fetchApi.mockClear(); }); - it("should handle cursor up", () => { - store.getState().flows = reduceFlows(flows, flowsActions.select("2")); - store.dispatch(createKeyEvent("k")); - expect(store.getActions()).toEqual([ - { flowIds: ["1"], type: flowsActions.SELECT }, - ]); - - store.clearActions(); - store.dispatch(createKeyEvent("ArrowUp")); - expect(store.getActions()).toEqual([ - { flowIds: ["1"], type: flowsActions.SELECT }, - ]); - }); - - it("should handle cursor down", () => { + it("should handle cursor up/down", () => { + const store = makeStore(); + // down store.dispatch(createKeyEvent("j")); - expect(store.getActions()).toEqual([ - { flowIds: ["3"], type: flowsActions.SELECT }, - ]); - - store.clearActions(); + expect(store.getState().flows.selected).toEqual(["2"]); store.dispatch(createKeyEvent("ArrowDown")); - expect(store.getActions()).toEqual([ - { flowIds: ["3"], type: flowsActions.SELECT }, - ]); - }); + expect(store.getState().flows.selected).toEqual(["3"]); - it("should handle page down", () => { - store.dispatch(createKeyEvent(" ")); - expect(store.getActions()).toEqual([ - { flowIds: ["12"], type: flowsActions.SELECT }, - ]); - - store.getState().flows = reduceFlows(flows, flowsActions.select("1")); - store.clearActions(); - store.dispatch(createKeyEvent("PageDown")); - expect(store.getActions()).toEqual([ - { flowIds: ["11"], type: flowsActions.SELECT }, - ]); + // up + store.dispatch(createKeyEvent("k")); + expect(store.getState().flows.selected).toEqual(["2"]); + store.dispatch(createKeyEvent("ArrowUp")); + expect(store.getState().flows.selected).toEqual(["1"]); + store.dispatch(createKeyEvent("ArrowUp")); + expect(store.getState().flows.selected).toEqual(["1"]); }); - it("should handle page up", () => { - store.getState().flows = reduceFlows(flows, flowsActions.select("11")); + it("should handle scrolling", () => { + const store = makeStore(); + store.dispatch(createKeyEvent("PageDown")); + expect(store.getState().flows.selected).toEqual(["11"]); + store.dispatch(createKeyEvent("End")); + expect(store.getState().flows.selected).toEqual(["12"]); store.dispatch(createKeyEvent("PageUp")); - expect(store.getActions()).toEqual([ - { flowIds: ["1"], type: flowsActions.SELECT }, - ]); - }); - - it("should handle select first", () => { + expect(store.getState().flows.selected).toEqual(["2"]); store.dispatch(createKeyEvent("Home")); - expect(store.getActions()).toEqual([ - { flowIds: ["1"], type: flowsActions.SELECT }, - ]); - }); - - it("should handle select last", () => { - store.getState().flows = reduceFlows(flows, flowsActions.select("1")); - store.dispatch(createKeyEvent("End")); - expect(store.getActions()).toEqual([ - { flowIds: ["12"], type: flowsActions.SELECT }, - ]); + expect(store.getState().flows.selected).toEqual(["1"]); }); it("should handle deselect", () => { + const store = makeStore(); store.dispatch(createKeyEvent("Escape")); - expect(store.getActions()).toEqual([ - { flowIds: [], type: flowsActions.SELECT }, - ]); + expect(store.getState().flows.selected).toEqual([]); }); it("should handle switch to left tab", () => { + const store = makeStore(); + expect(store.getState().ui.flow.tab).toBe("request"); store.dispatch(createKeyEvent("ArrowLeft")); - expect(store.getActions()).toEqual([ - { tab: "timing", type: UIActions.SET_TAB }, - ]); + expect(store.getState().ui.flow.tab).toBe("comment"); }); it("should handle switch to right tab", () => { + const store = makeStore(); + expect(store.getState().ui.flow.tab).toBe("request"); store.dispatch(createKeyEvent("Tab")); - expect(store.getActions()).toEqual([ - { tab: "response", type: UIActions.SET_TAB }, - ]); - - store.clearActions(); + expect(store.getState().ui.flow.tab).toBe("response"); store.dispatch(createKeyEvent("ArrowRight")); - expect(store.getActions()).toEqual([ - { tab: "response", type: UIActions.SET_TAB }, - ]); + expect(store.getState().ui.flow.tab).toBe("connection"); }); it("should handle delete action", () => { + const store = makeStore(); store.dispatch(createKeyEvent("d")); - expect(fetchApi).toBeCalledWith("/flows/1", { method: "DELETE" }); + expect(fetchApi).toHaveBeenCalledWith("/flows/1", { method: "DELETE" }); }); it("should handle create action", () => { + const store = makeStore(); store.dispatch(createKeyEvent("n")); - expect(runCommand).toBeCalledWith( + expect(runCommand).toHaveBeenCalledWith( "view.flows.create", "get", - "https://example.com/" + "https://example.com/", ); }); it("should handle duplicate action", () => { + const store = makeStore(); store.dispatch(createKeyEvent("D")); - expect(fetchApi).toBeCalledWith("/flows/1/duplicate", { + expect(fetchApi).toHaveBeenCalledWith("/flows/1/duplicate", { method: "POST", }); }); it("should handle resume action", () => { + const store = makeStore(); // resume all store.dispatch(createKeyEvent("A")); - expect(fetchApi).toBeCalledWith("/flows/resume", { method: "POST" }); + expect(fetchApi).toHaveBeenCalledWith("/flows/resume", { + method: "POST", + }); // resume store.getState().flows.byId[ store.getState().flows.selected[0] ].intercepted = true; store.dispatch(createKeyEvent("a")); - expect(fetchApi).toBeCalledWith("/flows/1/resume", { method: "POST" }); + expect(fetchApi).toHaveBeenCalledWith("/flows/1/resume", { + method: "POST", + }); }); it("should handle replay action", () => { + const store = makeStore(); store.dispatch(createKeyEvent("r")); - expect(fetchApi).toBeCalledWith("/flows/1/replay", { method: "POST" }); + expect(fetchApi).toHaveBeenCalledWith("/flows/1/replay", { + method: "POST", + }); }); it("should handle revert action", () => { - store.getState().flows.byId[ - store.getState().flows.selected[0] - ].modified = true; + const store = makeStore(); store.dispatch(createKeyEvent("v")); - expect(fetchApi).toBeCalledWith("/flows/1/revert", { method: "POST" }); + expect(fetchApi).toHaveBeenCalledWith("/flows/1/revert", { + method: "POST", + }); }); it("should handle kill action", () => { + const store = makeStore(); // kill all store.dispatch(createKeyEvent("X")); - expect(fetchApi).toBeCalledWith("/flows/kill", { method: "POST" }); + expect(fetchApi).toHaveBeenCalledWith("/flows/kill", { + method: "POST", + }); // kill store.dispatch(createKeyEvent("x")); - expect(fetchApi).toBeCalledWith("/flows/1/kill", { method: "POST" }); + expect(fetchApi).toHaveBeenCalledWith("/flows/1/kill", { + method: "POST", + }); }); it("should handle clear action", () => { + const store = makeStore(); store.dispatch(createKeyEvent("z")); - expect(fetchApi).toBeCalledWith("/clear", { method: "POST" }); + expect(fetchApi).toHaveBeenCalledWith("/clear", { method: "POST" }); }); it("should stop on some action with no flow is selected", () => { - store.getState().flows = reduceFlows(undefined, {}); + const store = makeStore(); + store.dispatch(flowsActions.select(undefined)); store.dispatch(createKeyEvent("ArrowLeft")); store.dispatch(createKeyEvent("Tab")); store.dispatch(createKeyEvent("ArrowRight")); store.dispatch(createKeyEvent("D")); - expect(fetchApi).not.toBeCalled(); + expect(fetchApi).not.toHaveBeenCalled(); }); it("should do nothing when Ctrl and undefined key is pressed ", () => { + const store = makeStore(); store.dispatch(createKeyEvent("Backspace", true)); store.dispatch(createKeyEvent(0)); - expect(fetchApi).not.toBeCalled(); + expect(fetchApi).not.toHaveBeenCalled(); }); it("should close modal", () => { - store.getState().ui.modal.activeModal = true; + const store = makeStore(); + store.dispatch(modalActions.setActiveModal("OptionModal")); + expect(store.getState().ui.modal.activeModal).toEqual("OptionModal"); store.dispatch(createKeyEvent("Escape")); - expect(store.getActions()).toEqual([{ type: modalActions.HIDE_MODAL }]); + expect(store.getState().ui.modal.activeModal).toEqual(undefined); }); }); diff --git a/web/src/js/__tests__/ducks/ui/modalSpec.tsx b/web/src/js/__tests__/ducks/ui/modalSpec.tsx index 7773ee561f..1a31a33670 100644 --- a/web/src/js/__tests__/ducks/ui/modalSpec.tsx +++ b/web/src/js/__tests__/ducks/ui/modalSpec.tsx @@ -6,12 +6,15 @@ describe("modal reducer", () => { }); it("should handle setActiveModal action", () => { - let state = reduceModal(undefined, ModalActions.setActiveModal("foo")); + const state = reduceModal( + undefined, + ModalActions.setActiveModal("foo"), + ); expect(state).toEqual({ activeModal: "foo" }); }); it("should handle hideModal action", () => { - let state = reduceModal(undefined, ModalActions.hideModal()); + const state = reduceModal(undefined, ModalActions.hideModal()); expect(state).toEqual({ activeModal: undefined }); }); }); diff --git a/web/src/js/__tests__/ducks/ui/optionEditorSpec.tsx b/web/src/js/__tests__/ducks/ui/optionEditorSpec.tsx index 814e782368..45047f0e9e 100644 --- a/web/src/js/__tests__/ducks/ui/optionEditorSpec.tsx +++ b/web/src/js/__tests__/ducks/ui/optionEditorSpec.tsx @@ -1,6 +1,5 @@ import reduceOptionsEditor, * as optionsEditorActions from "../../../ducks/ui/optionsEditor"; import { HIDE_MODAL } from "../../../ducks/ui/modal"; -import { OptionsState } from "../../../ducks/_options_gen"; describe("optionsEditor reducer", () => { it("should return initial state", () => { @@ -8,9 +7,9 @@ describe("optionsEditor reducer", () => { }); it("should handle option update start", () => { - let state = reduceOptionsEditor( + const state = reduceOptionsEditor( undefined, - optionsEditorActions.startUpdate("foo", "bar") + optionsEditorActions.startUpdate("foo", "bar"), ); expect(state).toEqual({ foo: { error: false, isUpdating: true, value: "bar" }, @@ -21,19 +20,19 @@ describe("optionsEditor reducer", () => { expect( reduceOptionsEditor( undefined, - optionsEditorActions.updateSuccess("foo") - ) + optionsEditorActions.updateSuccess("foo"), + ), ).toEqual({ foo: undefined }); }); it("should handle option update error", () => { let state = reduceOptionsEditor( undefined, - optionsEditorActions.startUpdate("foo", "bar") + optionsEditorActions.startUpdate("foo", "bar"), ); state = reduceOptionsEditor( state, - optionsEditorActions.updateError("foo", "errorMsg") + optionsEditorActions.updateError("foo", "errorMsg"), ); expect(state).toEqual({ foo: { error: "errorMsg", isUpdating: false, value: "bar" }, @@ -41,11 +40,11 @@ describe("optionsEditor reducer", () => { // boolean type state = reduceOptionsEditor( undefined, - optionsEditorActions.startUpdate("foo", true) + optionsEditorActions.startUpdate("foo", true), ); state = reduceOptionsEditor( state, - optionsEditorActions.updateError("foo", "errorMsg") + optionsEditorActions.updateError("foo", "errorMsg"), ); expect(state).toEqual({ foo: { error: "errorMsg", isUpdating: false, value: false }, @@ -54,7 +53,7 @@ describe("optionsEditor reducer", () => { it("should handle hide modal", () => { expect(reduceOptionsEditor(undefined, { type: HIDE_MODAL })).toEqual( - {} + {}, ); }); }); diff --git a/web/src/js/__tests__/ducks/utils/storeSpec.tsx b/web/src/js/__tests__/ducks/utils/storeSpec.tsx index 6b4d6d6b9a..48cd9b692b 100644 --- a/web/src/js/__tests__/ducks/utils/storeSpec.tsx +++ b/web/src/js/__tests__/ducks/utils/storeSpec.tsx @@ -13,9 +13,9 @@ describe("store reducer", () => { }); it("should handle add action", () => { - let a = { id: "1" }, - b = { id: "9" }, - state = reduce(undefined, {}); + const a = { id: "1" }; + const b = { id: "9" }; + let state = reduce(undefined, {}); expect((state = reduce(state, storeActions.add(a)))).toEqual({ byId: { "1": a }, listIndex: { "1": 0 }, @@ -33,14 +33,14 @@ describe("store reducer", () => { }); // add item and sort them - let c = { id: "0" }; + const c = { id: "0" }; expect( reduce( state, storeActions.add(c, undefined, (a, b) => { return a.id > b.id ? 1 : -1; - }) - ) + }), + ), ).toEqual({ byId: { ...state.byId, "0": c }, list: [...state.list, c], @@ -51,8 +51,8 @@ describe("store reducer", () => { }); it("should not add the item with duplicated id", () => { - let a = { id: "1" }, - state = reduce(undefined, storeActions.add(a)); + const a = { id: "1" }; + const state = reduce(undefined, storeActions.add(a)); expect(reduce(state, storeActions.add(a))).toEqual(state); }); @@ -61,9 +61,9 @@ describe("store reducer", () => { foo: string; } - let a: TItem = { id: "1", foo: "foo" }, - updated = { ...a, foo: "bar" }, - state = reduce(undefined, storeActions.add(a)); + const a: TItem = { id: "1", foo: "foo" }; + const updated = { ...a, foo: "bar" }; + const state = reduce(undefined, storeActions.add(a)); expect(reduce(state, storeActions.update(updated))).toEqual({ byId: { 1: updated }, list: [updated], @@ -74,14 +74,14 @@ describe("store reducer", () => { }); it("should handle update action with filter", () => { - let a = { id: "0" }, - b = { id: "1" }, - state = reduce(undefined, storeActions.receive([a, b])); + const a = { id: "0" }; + const b = { id: "1" }; + let state = reduce(undefined, storeActions.receive([a, b])); state = reduce( state, storeActions.update(b, (item) => { return item.id !== "1"; - }) + }), ); expect(state).toEqual({ byId: { "0": a, "1": b }, @@ -95,8 +95,8 @@ describe("store reducer", () => { state, storeActions.update(b, (item) => { return item.id !== "0"; - }) - ) + }), + ), ).toEqual({ byId: { "0": a, "1": b }, list: [a, b], @@ -107,16 +107,16 @@ describe("store reducer", () => { }); it("should handle update action with sort", () => { - let a = { id: "2" }, - b = { id: "3" }, - state = reduce(undefined, storeActions.receive([a, b])); + const a = { id: "2" }; + const b = { id: "3" }; + const state = reduce(undefined, storeActions.receive([a, b])); expect( reduce( state, storeActions.update(b, undefined, (a, b) => { return b.id > a.id ? 1 : -1; - }) - ) + }), + ), ).toEqual({ // sort by id in descending order byId: { "2": a, "3": b }, @@ -126,14 +126,14 @@ describe("store reducer", () => { viewIndex: { "2": 1, "3": 0 }, }); - let state1 = reduce(undefined, storeActions.receive([b, a])); + const state1 = reduce(undefined, storeActions.receive([b, a])); expect( reduce( state1, storeActions.update(b, undefined, (a, b) => { return a.id > b.id ? 1 : -1; - }) - ) + }), + ), ).toEqual({ // sort by id in ascending order byId: { "2": a, "3": b }, @@ -145,16 +145,16 @@ describe("store reducer", () => { }); it("should set filter", () => { - let a = { id: "1" }, - b = { id: "2" }, - state = reduce(undefined, storeActions.receive([a, b])); + const a = { id: "1" }; + const b = { id: "2" }; + const state = reduce(undefined, storeActions.receive([a, b])); expect( reduce( state, storeActions.setFilter((item) => { return item.id !== "1"; - }) - ) + }), + ), ).toEqual({ byId: { "1": a, "2": b }, list: [a, b], @@ -165,16 +165,16 @@ describe("store reducer", () => { }); it("should set sort", () => { - let a = { id: "1" }, - b = { id: "2" }, - state = reduce(undefined, storeActions.receive([a, b])); + const a = { id: "1" }; + const b = { id: "2" }; + const state = reduce(undefined, storeActions.receive([a, b])); expect( reduce( state, storeActions.setSort((a, b) => { return b.id > a.id ? 1 : -1; - }) - ) + }), + ), ).toEqual({ byId: { 1: a, 2: b }, list: [a, b], @@ -185,9 +185,9 @@ describe("store reducer", () => { }); it("should handle remove action", () => { - let a = { id: "1" }, - b = { id: "2" }, - state = reduce(undefined, storeActions.receive([a, b])); + const a = { id: "1" }; + const b = { id: "2" }; + const state = reduce(undefined, storeActions.receive([a, b])); expect(reduce(state, storeActions.remove("1"))).toEqual({ byId: { "2": b }, list: [b], @@ -200,9 +200,9 @@ describe("store reducer", () => { }); it("should handle receive list", () => { - let a = { id: "1" }, - b = { id: "2" }, - list = [a, b]; + const a = { id: "1" }; + const b = { id: "2" }; + const list = [a, b]; expect(reduce(undefined, storeActions.receive(list))).toEqual({ byId: { "1": a, "2": b }, list: [a, b], diff --git a/web/src/js/__tests__/flow/utilsSpec.tsx b/web/src/js/__tests__/flow/utilsSpec.tsx index 271aa04936..4c9d08a1a7 100644 --- a/web/src/js/__tests__/flow/utilsSpec.tsx +++ b/web/src/js/__tests__/flow/utilsSpec.tsx @@ -5,26 +5,26 @@ import { HTTPFlow } from "../../flow"; describe("MessageUtils", () => { it("should be possible to get first header", () => { - let tflow = TFlow(); + const tflow = TFlow(); expect( - utils.MessageUtils.get_first_header(tflow.request, /header/) + utils.MessageUtils.get_first_header(tflow.request, /header/), ).toEqual("qvalue"); expect( - utils.MessageUtils.get_first_header(tflow.request, /123/) + utils.MessageUtils.get_first_header(tflow.request, /123/), ).toEqual(undefined); }); it("should be possible to get Content-Type", () => { - let tflow = TFlow(); + const tflow = TFlow(); tflow.request.headers = [["Content-Type", "text/html"]]; expect(utils.MessageUtils.getContentType(tflow.request)).toEqual( - "text/html" + "text/html", ); }); it("should be possible to match header", () => { - let h1 = ["foo", "bar"], - msg = { headers: [h1] }; + const h1 = ["foo", "bar"]; + const msg = { headers: [h1] }; expect(utils.MessageUtils.match_header(msg, /foo/i)).toEqual(h1); expect(utils.MessageUtils.match_header(msg, /123/i)).toBeFalsy(); }); @@ -32,38 +32,38 @@ describe("MessageUtils", () => { it("should be possible to get content URL", () => { const flow = TFlow(); // request - let view = "bar"; + const view = "bar"; expect( - utils.MessageUtils.getContentURL(flow, flow.request, view) + utils.MessageUtils.getContentURL(flow, flow.request, view), ).toEqual( - "./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/request/content/bar.json" + "./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/request/content/bar.json", ); expect( - utils.MessageUtils.getContentURL(flow, flow.request, "") + utils.MessageUtils.getContentURL(flow, flow.request, ""), ).toEqual( - "./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/request/content.data" + "./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/request/content.data", ); // response expect( - utils.MessageUtils.getContentURL(flow, flow.response, view) + utils.MessageUtils.getContentURL(flow, flow.response, view), ).toEqual( - "./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content/bar.json" + "./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content/bar.json", ); }); }); describe("RequestUtils", () => { it("should be possible prettify url", () => { - let flow = TFlow(); + const flow = TFlow(); expect(utils.RequestUtils.pretty_url(flow.request)).toEqual( - "http://address:22/path" + "http://address:22/path", ); }); }); describe("parseUrl", () => { it("should be possible to parse url", () => { - let url = "http://foo:4444/bar"; + const url = "http://foo:4444/bar"; expect(utils.parseUrl(url)).toEqual({ port: 4444, scheme: "http", @@ -90,7 +90,7 @@ it("should be possible to get a start time", () => { }); it("should be possible to get an end time", () => { - let f: HTTPFlow = THTTPFlow(); + const f: HTTPFlow = THTTPFlow(); expect(utils.endTime(f)).toEqual(946681205); f.websocket = undefined; expect(utils.endTime(f)).toEqual(946681203); diff --git a/web/src/js/__tests__/modes/dnsSpec.ts b/web/src/js/__tests__/modes/dnsSpec.ts new file mode 100644 index 0000000000..786e7d2d77 --- /dev/null +++ b/web/src/js/__tests__/modes/dnsSpec.ts @@ -0,0 +1,31 @@ +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, parseRaw, DnsState } from "../../modes/dns"; + +describe("getSpec dns mode", () => { + it("should return the correct mode config", () => { + const modes = { + dns: [ + { + active: true, + listen_host: "localhost", + listen_port: 8082, + }, + ], + } as ModesState; + const mode = getSpec(modes.dns[0]); + expect(mode).toBe("dns@localhost:8082"); + }); +}); + +describe("parseRaw dns mode", () => { + it("should parse", () => { + const parsed = parseRaw(parseSpec("dns@localhost:8082")); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + listen_host: "localhost", + listen_port: 8082, + } as DnsState); + }); +}); diff --git a/web/src/js/__tests__/modes/indexSpec.ts b/web/src/js/__tests__/modes/indexSpec.ts new file mode 100644 index 0000000000..31ac205400 --- /dev/null +++ b/web/src/js/__tests__/modes/indexSpec.ts @@ -0,0 +1,57 @@ +import { includeListenAddress, parseSpec } from "../../modes"; + +describe("includeListenAddress", () => { + it("should keep mode as-is if not port is specified", () => { + const mode = {}; + const result = includeListenAddress("regular", mode); + expect(result).toEqual("regular"); + }); + + it("should return array with mode name and listen_port if mode is active with listen_port", () => { + const mode = { + listen_port: 8080, + }; + const result = includeListenAddress("regular", mode); + expect(result).toEqual("regular@8080"); + }); + + it("should return array with mode name, listen_host, and listen_port if mode is active with listen_host and listen_port", () => { + const mode = { + listen_host: "localhost", + listen_port: 8080, + }; + const result = includeListenAddress("regular", mode); + expect(result).toEqual("regular@localhost:8080"); + }); +}); + +describe("parseSpec", () => { + it("should parse regular mode with host and port", () => { + const modeConfig = "regular@localhost:8081"; + const result = parseSpec(modeConfig); + expect(result).toEqual({ + name: "regular", + full_spec: "regular@localhost:8081", + data: "", + listen_host: "localhost", + listen_port: 8081, + }); + }); + + it("should parse local mode with data", () => { + const modeConfig = "local:curl,http"; + const result = parseSpec(modeConfig); + expect(result).toEqual({ + name: "local", + data: "curl,http", + full_spec: "local:curl,http", + listen_host: undefined, + listen_port: undefined, + }); + }); + + it("should throw an error for invalid port", () => { + const modeConfig = "regular@99999"; + expect(() => parseSpec(modeConfig)).toThrow("invalid port: 99999"); + }); +}); diff --git a/web/src/js/__tests__/modes/localSpec.ts b/web/src/js/__tests__/modes/localSpec.ts new file mode 100644 index 0000000000..77b5440a24 --- /dev/null +++ b/web/src/js/__tests__/modes/localSpec.ts @@ -0,0 +1,29 @@ +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, LocalState, parseRaw } from "../../modes/local"; + +describe("getSpec local mode", () => { + it("should return the correct mode config", () => { + const modes = { + local: [ + { + active: true, + selectedProcesses: "curl,http", + }, + ], + } as ModesState; + const mode = getSpec(modes.local[0]); + expect(mode).toBe("local:curl,http"); + }); +}); + +describe("parseRaw local mode", () => { + it("should parse", () => { + const parsed = parseRaw(parseSpec("local:curl,http")); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + selectedProcesses: "curl,http", + } as LocalState); + }); +}); diff --git a/web/src/js/__tests__/modes/regularSpec.ts b/web/src/js/__tests__/modes/regularSpec.ts new file mode 100644 index 0000000000..40e38fa75b --- /dev/null +++ b/web/src/js/__tests__/modes/regularSpec.ts @@ -0,0 +1,31 @@ +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, parseRaw, RegularState } from "../../modes/regular"; + +describe("getSpec regular mode", () => { + it("should return the correct mode config", () => { + const modes = { + regular: [ + { + active: true, + listen_host: "localhost", + listen_port: 8082, + }, + ], + } as ModesState; + const mode = getSpec(modes.regular[0]); + expect(mode).toBe("regular@localhost:8082"); + }); +}); + +describe("parseRaw regular mode", () => { + it("should parse", () => { + const parsed = parseRaw(parseSpec("regular@localhost:8082")); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + listen_host: "localhost", + listen_port: 8082, + } as RegularState); + }); +}); diff --git a/web/src/js/__tests__/modes/reverseSpec.ts b/web/src/js/__tests__/modes/reverseSpec.ts new file mode 100644 index 0000000000..aa88c4e79c --- /dev/null +++ b/web/src/js/__tests__/modes/reverseSpec.ts @@ -0,0 +1,38 @@ +import { ReverseProxyProtocols } from "../../backends/consts"; +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, parseRaw, ReverseState } from "../../modes/reverse"; + +describe("getSpec reverse mode", () => { + it("should return the correct mode config", () => { + const modes = { + reverse: [ + { + active: true, + protocol: ReverseProxyProtocols.HTTPS, + destination: "example.com:8085", + listen_host: "localhost", + listen_port: 8082, + }, + ], + } as ModesState; + const mode = getSpec(modes.reverse[0]); + expect(mode).toBe("reverse:https://example.com:8085@localhost:8082"); + }); +}); + +describe("parseRaw reverse mode", () => { + it("should parse", () => { + const parsed = parseRaw( + parseSpec("reverse:https://example.com:8085@localhost:8082"), + ); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + protocol: ReverseProxyProtocols.HTTPS, + destination: "example.com:8085", + listen_host: "localhost", + listen_port: 8082, + } as ReverseState); + }); +}); diff --git a/web/src/js/__tests__/modes/socksSpec.ts b/web/src/js/__tests__/modes/socksSpec.ts new file mode 100644 index 0000000000..f0b4f79fa4 --- /dev/null +++ b/web/src/js/__tests__/modes/socksSpec.ts @@ -0,0 +1,31 @@ +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, parseRaw, SocksState } from "../../modes/socks"; + +describe("getSpec socks mode", () => { + it("should return the correct mode config", () => { + const modes = { + socks: [ + { + active: true, + listen_host: "localhost", + listen_port: 8082, + }, + ], + } as ModesState; + const mode = getSpec(modes.socks[0]); + expect(mode).toBe("socks5@localhost:8082"); + }); +}); + +describe("parseRaw socks mode", () => { + it("should parse", () => { + const parsed = parseRaw(parseSpec("socks5@localhost:8082")); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + listen_host: "localhost", + listen_port: 8082, + } as SocksState); + }); +}); diff --git a/web/src/js/__tests__/modes/transparentSpec.ts b/web/src/js/__tests__/modes/transparentSpec.ts new file mode 100644 index 0000000000..1a9815d1a1 --- /dev/null +++ b/web/src/js/__tests__/modes/transparentSpec.ts @@ -0,0 +1,31 @@ +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, parseRaw, TransparentState } from "../../modes/transparent"; + +describe("getSpec transparent mode", () => { + it("should return the correct mode config", () => { + const modes = { + transparent: [ + { + active: true, + listen_host: "localhost", + listen_port: 8082, + }, + ], + } as ModesState; + const mode = getSpec(modes.transparent[0]); + expect(mode).toBe("transparent@localhost:8082"); + }); +}); + +describe("parseRaw transparent mode", () => { + it("should parse", () => { + const parsed = parseRaw(parseSpec("transparent@localhost:8082")); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + listen_host: "localhost", + listen_port: 8082, + } as TransparentState); + }); +}); diff --git a/web/src/js/__tests__/modes/upstreamSpec.ts b/web/src/js/__tests__/modes/upstreamSpec.ts new file mode 100644 index 0000000000..05d6efa740 --- /dev/null +++ b/web/src/js/__tests__/modes/upstreamSpec.ts @@ -0,0 +1,35 @@ +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, parseRaw, UpstreamState } from "../../modes/upstream"; + +describe("getSpec upstream mode", () => { + it("should return the correct mode config", () => { + const modes = { + upstream: [ + { + active: true, + destination: "https://example.com:8085", + listen_host: "localhost", + listen_port: 8082, + }, + ], + } as ModesState; + const mode = getSpec(modes.upstream[0]); + expect(mode).toBe("upstream:https://example.com:8085@localhost:8082"); + }); +}); + +describe("parseRaw upstream mode", () => { + it("should parse", () => { + const parsed = parseRaw( + parseSpec("upstream:https://example.com:8085@localhost:8082"), + ); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + destination: "https://example.com:8085", + listen_host: "localhost", + listen_port: 8082, + } as UpstreamState); + }); +}); diff --git a/web/src/js/__tests__/modes/wireguardSpec.ts b/web/src/js/__tests__/modes/wireguardSpec.ts new file mode 100644 index 0000000000..ef1d983263 --- /dev/null +++ b/web/src/js/__tests__/modes/wireguardSpec.ts @@ -0,0 +1,36 @@ +import { ModesState } from "../../ducks/modes"; +import { parseSpec } from "../../modes"; +import { getSpec, parseRaw, WireguardState } from "../../modes/wireguard"; + +describe("getSpec wireguard mode", () => { + it("should return the correct mode config", () => { + const modes = { + wireguard: [ + { + active: true, + listen_host: "localhost", + listen_port: 8082, + }, + { + active: true, + file_path: "~/test", + }, + ], + } as ModesState; + expect(getSpec(modes.wireguard[0])).toBe("wireguard@localhost:8082"); + expect(getSpec(modes.wireguard[1])).toBe("wireguard:~/test"); + }); +}); + +describe("parseRaw wireguard mode", () => { + it("should parse", () => { + const parsed = parseRaw(parseSpec("wireguard@localhost:8082")); + expect(parsed).toEqual({ + active: true, + ui_id: parsed.ui_id, + file_path: "", + listen_host: "localhost", + listen_port: 8082, + } as WireguardState); + }); +}); diff --git a/web/src/js/__tests__/test-utils.tsx b/web/src/js/__tests__/test-utils.tsx index fc5736fdc4..b68b481e9b 100644 --- a/web/src/js/__tests__/test-utils.tsx +++ b/web/src/js/__tests__/test-utils.tsx @@ -3,19 +3,14 @@ import { render as rtlRender } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import "@testing-library/jest-dom"; import { Provider } from "react-redux"; -// Import your own reducer -import { createAppStore } from "../ducks"; -import { testState } from "./ducks/tutils"; +import { TStore } from "./ducks/tutils"; // re-export everything export { waitFor, fireEvent, act, screen } from "@testing-library/react"; export { userEvent }; -export function render( - ui, - { store = createAppStore(testState), ...renderOptions } = {} -) { - function Wrapper({ children }) { +export function render(ui, { store = TStore(), ...renderOptions } = {}) { + function Wrapper({ children }: { children: React.ReactNode }) { return {children}; } diff --git a/web/src/js/__tests__/urlStateSpec.tsx b/web/src/js/__tests__/urlStateSpec.tsx index e530acc954..9f24feca02 100644 --- a/web/src/js/__tests__/urlStateSpec.tsx +++ b/web/src/js/__tests__/urlStateSpec.tsx @@ -1,11 +1,12 @@ -import initialize from "../urlState"; -import { updateStoreFromUrl, updateUrlFromStore } from "../urlState"; +import initialize, { + updateStoreFromUrl, + updateUrlFromStore, +} from "../urlState"; -import reduceFlows from "../ducks/flows"; +import reduceFlows, * as flowsActions from "../ducks/flows"; import reduceUI from "../ducks/ui/index"; import reduceEventLog from "../ducks/eventLog"; import reduceCommandBar from "../ducks/commandBar"; -import * as flowsActions from "../ducks/flows"; import configureStore from "redux-mock-store"; @@ -15,7 +16,7 @@ history.replaceState = jest.fn(); describe("updateStoreFromUrl", () => { it("should handle search query", () => { window.location.hash = "#/flows?s=foo"; - let store = mockStore(); + const store = mockStore(); updateStoreFromUrl(store); expect(store.getActions()).toEqual([ { filter: "foo", type: "FLOWS_SET_FILTER" }, @@ -24,7 +25,7 @@ describe("updateStoreFromUrl", () => { it("should handle highlight query", () => { window.location.hash = "#/flows?h=foo"; - let store = mockStore(); + const store = mockStore(); updateStoreFromUrl(store); expect(store.getActions()).toEqual([ { highlight: "foo", type: "FLOWS_SET_HIGHLIGHT" }, @@ -33,8 +34,8 @@ describe("updateStoreFromUrl", () => { it("should handle show event log", () => { window.location.hash = "#/flows?e=true"; - let initialState = { eventLog: reduceEventLog(undefined, {}) }, - store = mockStore(initialState); + const initialState = { eventLog: reduceEventLog(undefined, {}) }; + const store = mockStore(initialState); updateStoreFromUrl(store); expect(store.getActions()).toEqual([ { type: "EVENTS_TOGGLE_VISIBILITY" }, @@ -44,16 +45,16 @@ describe("updateStoreFromUrl", () => { it("should handle unimplemented query argument", () => { window.location.hash = "#/flows?foo=bar"; console.error = jest.fn(); - let store = mockStore(); + const store = mockStore(); updateStoreFromUrl(store); expect(console.error).toBeCalledWith( - "unimplemented query arg: foo=bar" + "unimplemented query arg: foo=bar", ); }); it("should select flow and tab", () => { window.location.hash = "#/flows/123/request"; - let store = mockStore(); + const store = mockStore(); updateStoreFromUrl(store); expect(store.getActions()).toEqual([ { @@ -69,7 +70,7 @@ describe("updateStoreFromUrl", () => { }); describe("updateUrlFromStore", () => { - let initialState = { + const initialState = { flows: reduceFlows(undefined, { type: "other" }), ui: reduceUI(undefined, { type: "other" }), eventLog: reduceEventLog(undefined, { type: "other" }), @@ -77,29 +78,29 @@ describe("updateUrlFromStore", () => { }; it("should update initial url", () => { - let store = mockStore(initialState); + const store = mockStore(initialState); updateUrlFromStore(store); expect(history.replaceState).toBeCalledWith(undefined, "", "/#/flows"); }); it("should update url", () => { - let flows = reduceFlows(undefined, flowsActions.select("123")), - state = { - ...initialState, - flows: reduceFlows(flows, flowsActions.setFilter("~u foo")), - }, - store = mockStore(state); + const flows = reduceFlows(undefined, flowsActions.select("123")); + const state = { + ...initialState, + flows: reduceFlows(flows, flowsActions.setFilter("~u foo")), + }; + const store = mockStore(state); updateUrlFromStore(store); expect(history.replaceState).toBeCalledWith( undefined, "", - "/#/flows/123/request?s=~u%20foo" + "/#/flows/123/request?s=~u%20foo", ); }); }); describe("initialize", () => { - let initialState = { + const initialState = { flows: reduceFlows(undefined, { type: "other" }), ui: reduceUI(undefined, { type: "other" }), eventLog: reduceEventLog(undefined, { type: "other" }), @@ -107,7 +108,7 @@ describe("initialize", () => { }; it("should handle initial state", () => { - let store = mockStore(initialState); + const store = mockStore(initialState); initialize(store); store.dispatch({ type: "foo" }); }); diff --git a/web/src/js/__tests__/utilsSpec.tsx b/web/src/js/__tests__/utilsSpec.tsx index b91fa84114..db03e9f587 100644 --- a/web/src/js/__tests__/utilsSpec.tsx +++ b/web/src/js/__tests__/utilsSpec.tsx @@ -23,10 +23,10 @@ describe("formatTimeDelta", () => { describe("formatTimeStamp", () => { it("should return formatted time", () => { expect( - utils.formatTimeStamp(1483228800, { milliseconds: false }) + utils.formatTimeStamp(1483228800, { milliseconds: false }), ).toEqual("2017-01-01 00:00:00"); expect( - utils.formatTimeStamp(1483228800, { milliseconds: true }) + utils.formatTimeStamp(1483228800, { milliseconds: true }), ).toEqual("2017-01-01 00:00:00.000"); }); }); @@ -34,7 +34,7 @@ describe("formatTimeStamp", () => { describe("formatAddress", () => { it("should return formatted addresses", () => { expect(utils.formatAddress(["127.0.0.1", 8080])).toEqual( - "127.0.0.1:8080" + "127.0.0.1:8080", ); expect(utils.formatAddress(["::1", 8080])).toEqual("[::1]:8080"); }); @@ -42,10 +42,10 @@ describe("formatAddress", () => { describe("reverseString", () => { it("should return reversed string", () => { - let str1 = "abc", - str2 = "xyz"; + const str1 = "abc"; + const str2 = "xyz"; expect( - utils.reverseString(str1) > utils.reverseString(str2) + utils.reverseString(str1) > utils.reverseString(str2), ).toBeTruthy(); }); }); @@ -80,8 +80,8 @@ describe("fetchApi", () => { describe("getDiff", () => { it("should return json object including only the changed keys value pairs", () => { - let obj1 = { a: 1, b: { foo: 1 }, c: [3] }, - obj2 = { a: 1, b: { foo: 2 }, c: [4] }; + const obj1 = { a: 1, b: { foo: 1 }, c: [3] }; + const obj2 = { a: 1, b: { foo: 2 }, c: [4] }; expect(utils.getDiff(obj1, obj2)).toEqual({ b: { foo: 2 }, c: [4] }); }); }); diff --git a/web/src/js/app.tsx b/web/src/js/app.tsx index ae1e4697f6..1e8c96aadb 100644 --- a/web/src/js/app.tsx +++ b/web/src/js/app.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { render } from "react-dom"; +import { createRoot } from "react-dom/client"; import { Provider } from "react-redux"; import ProxyApp from "./components/ProxyApp"; @@ -10,12 +10,12 @@ import StaticBackend from "./backends/static"; import { store } from "./ducks"; useUrlState(store); -// @ts-ignore +// @ts-expect-error custom property on window if (window.MITMWEB_STATIC) { - // @ts-ignore + // @ts-expect-error new property on window for debugging window.backend = new StaticBackend(store); } else { - // @ts-ignore + // @ts-expect-error new property on window for debugging window.backend = new WebSocketBackend(store); } @@ -24,10 +24,11 @@ window.addEventListener("error", (e: ErrorEvent) => { }); document.addEventListener("DOMContentLoaded", () => { - render( + const container = document.getElementById("mitmproxy"); + const root = createRoot(container!); + root.render( , - document.getElementById("mitmproxy") ); }); diff --git a/web/src/js/backends/consts.ts b/web/src/js/backends/consts.ts new file mode 100644 index 0000000000..133a47f9b3 --- /dev/null +++ b/web/src/js/backends/consts.ts @@ -0,0 +1,12 @@ +/** Auto-generated by web/gen/backend_consts.py */ +export enum ReverseProxyProtocols { + HTTP = "http", + HTTPS = "https", + HTTP3 = "http3", + TLS = "tls", + DTLS = "dtls", + TCP = "tcp", + UDP = "udp", + DNS = "dns", + QUIC = "quic", +} diff --git a/web/src/js/backends/static.tsx b/web/src/js/backends/static.tsx index bb40bc43c5..992174b56b 100644 --- a/web/src/js/backends/static.tsx +++ b/web/src/js/backends/static.tsx @@ -29,7 +29,7 @@ export default class StaticBackend { } receive(resource, data) { - let type = `${resource}_RECEIVE`.toUpperCase(); + const type = `${resource}_RECEIVE`.toUpperCase(); this.store.dispatch({ type, cmd: "receive", resource, data }); } } diff --git a/web/src/js/backends/websocket.tsx b/web/src/js/backends/websocket.tsx index 58afa0b45b..34a3d44b9a 100644 --- a/web/src/js/backends/websocket.tsx +++ b/web/src/js/backends/websocket.tsx @@ -7,6 +7,8 @@ import { fetchApi } from "../utils"; import * as connectionActions from "../ducks/connection"; import { Store } from "redux"; import { RootState } from "../ducks"; +import { PayloadAction } from "@reduxjs/toolkit"; +import { BackendState } from "../ducks/backendState"; const CMD_RESET = "reset"; @@ -29,12 +31,12 @@ export default class WebsocketBackend { this.socket = new WebSocket( location.origin.replace("http", "ws") + location.pathname.replace(/\/$/, "") + - "/updates" + "/updates", ); this.socket.addEventListener("open", () => this.onOpen()); this.socket.addEventListener("close", (event) => this.onClose(event)); this.socket.addEventListener("message", (msg) => - this.onMessage(JSON.parse(msg.data)) + this.onMessage(JSON.parse(msg.data)), ); this.socket.addEventListener("error", (error) => this.onError(error)); } @@ -48,7 +50,7 @@ export default class WebsocketBackend { } fetchData(resource) { - let queue = []; + const queue = []; this.activeFetches[resource] = queue; fetchApi(`./${resource}`) .then((res) => res.json()) @@ -66,15 +68,23 @@ export default class WebsocketBackend { if (msg.resource in this.activeFetches) { this.activeFetches[msg.resource].push(msg); } else { - let type = `${msg.resource}_${msg.cmd}`.toUpperCase(); + const type = `${msg.resource}_${msg.cmd}`.toUpperCase(); this.store.dispatch({ type, ...msg }); } } receive(resource, data) { - let type = `${resource}_RECEIVE`.toUpperCase(); - this.store.dispatch({ type, cmd: "receive", resource, data }); - let queue = this.activeFetches[resource]; + const type = `${resource}_RECEIVE`.toUpperCase(); + if (resource === "state") { + this.store.dispatch({ + type, + payload: data, + } as PayloadAction); + } else { + // deprecated: these should be converted to payload actions as well. + this.store.dispatch({ type, cmd: "receive", resource, data }); + } + const queue = this.activeFetches[resource]; delete this.activeFetches[resource]; queue.forEach((msg) => this.onMessage(msg)); @@ -89,14 +99,14 @@ export default class WebsocketBackend { connectionActions.connectionError( `Connection closed at ${new Date().toUTCString()} with error code ${ closeEvent.code - }.` - ) + }.`, + ), ); console.error("websocket connection closed", closeEvent); } - onError(error) { + onError(...args) { // FIXME - console.error("websocket connection errored", arguments); + console.error("websocket connection errored", args); } } diff --git a/web/src/js/components/CaptureSetup.tsx b/web/src/js/components/CaptureSetup.tsx deleted file mode 100644 index a13681919e..0000000000 --- a/web/src/js/components/CaptureSetup.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import * as React from "react"; -import { useEffect, useRef } from "react"; -import { useAppSelector } from "../ducks"; -import { ServerInfo } from "../ducks/backendState"; -import { formatAddress } from "../utils"; -import QRCode from "qrcode"; - -export default function CaptureSetup() { - const servers = useAppSelector((state) => state.backendState.servers); - - let configure_action_text; - if (servers.length === 0) { - configure_action_text = ""; - } else if (servers.length === 1) { - configure_action_text = - "Configure your client to use the following proxy server:"; - } else { - configure_action_text = - "Configure your client to use one of the following proxy servers:"; - } - - return ( -
-

mitmproxy is running.

-

- No flows have been recorded yet. -
- {configure_action_text} -

-
    - {servers.map((server, i) => ( -
  • - -
  • - ))} -
- {/* -

You can also start additional servers:

-
    -
  • TODO
  • -
- */} -
- ); -} - -export function ServerDescription({ - description, - listen_addrs, - last_exception, - is_running, - full_spec, - wireguard_conf, -}: ServerInfo) { - const qrCode = useRef(null); - useEffect(() => { - if (wireguard_conf && qrCode.current) - QRCode.toCanvas(qrCode.current, wireguard_conf, { - margin: 0, - scale: 3, - }); - }, [wireguard_conf]); - - let listen_str; - const all_same_port = - listen_addrs.length === 1 || - (listen_addrs.length === 2 && - listen_addrs[0][1] === listen_addrs[1][1]); - const unbound = listen_addrs.every((addr) => - ["::", "0.0.0.0"].includes(addr[0]) - ); - if (all_same_port && unbound) { - listen_str = formatAddress(["*", listen_addrs[0][1]]); - } else { - listen_str = listen_addrs.map(formatAddress).join(" and "); - } - description = description[0].toUpperCase() + description.substr(1); - let desc, icon; - if (last_exception) { - icon = "fa-exclamation text-error"; - desc = ( - <> - {description} ({full_spec}): -
- {last_exception} - - ); - } else if (!is_running) { - icon = "fa-pause text-warning"; - desc = ( - <> - {description} ({full_spec}) - - ); - } else { - icon = "fa-check text-success"; - desc = `${description} listening at ${listen_str}.`; - - if (wireguard_conf) { - desc = ( - <> - {desc} -
-
{wireguard_conf}
- -
- - ); - } - } - return ( - <> - - {desc} - - ); -} diff --git a/web/src/js/components/CommandBar.tsx b/web/src/js/components/CommandBar.tsx index 42f3ef915a..78a74454b7 100644 --- a/web/src/js/components/CommandBar.tsx +++ b/web/src/js/components/CommandBar.tsx @@ -39,11 +39,11 @@ type ResultProps = { function getAvailableCommands( commands: AllCommands, - input: string = "" + input: string = "", ): string[] { if (!commands) return []; - let availableCommands: string[] = []; - for (const [command, args] of Object.entries(commands)) { + const availableCommands: string[] = []; + for (const command of Object.keys(commands)) { if (command.startsWith(input)) { availableCommands.push(command); } @@ -64,7 +64,7 @@ export function Results({ results }: ResultProps) { top: target.scrollHeight, behavior: "auto", }); - } + }, ); } }, []); @@ -90,7 +90,7 @@ export function CommandHelp({ description, availableCommands, }: CommandHelpProps) { - let argumentSuggestion: JSX.Element[] = []; + const argumentSuggestion: JSX.Element[] = []; for (let i: number = 0; i < nextArgs.length; i++) { if (i == currentArg) { argumentSuggestion.push({nextArgs[i]}); @@ -131,7 +131,7 @@ export default function CommandBar() { const [originalInput, setOriginalInput] = useState(""); const [currentCompletion, setCurrentCompletion] = useState(0); const [completionCandidate, setCompletionCandidate] = useState( - [] + [], ); const [availableCommands, setAvailableCommands] = useState([]); @@ -172,12 +172,12 @@ export default function CommandBar() { setDescription(allCommands[parts[0]]?.help || ""); setCompletionCandidate( - getAvailableCommands(allCommands, originalParts[0]) + getAvailableCommands(allCommands, originalParts[0]), ); setAvailableCommands(getAvailableCommands(allCommands, parts[0])); const nextArgs: string[] = allCommands[parts[0]]?.parameters.map( - (p) => p.name + (p) => p.name, ); if (nextArgs) { @@ -262,7 +262,7 @@ export default function CommandBar() { if (e.key === "Tab") { setInput(completionCandidate[currentCompletion]); setCurrentCompletion( - (currentCompletion + 1) % completionCandidate.length + (currentCompletion + 1) % completionCandidate.length, ); e.preventDefault(); } diff --git a/web/src/js/components/EventLog.jsx b/web/src/js/components/EventLog.tsx similarity index 63% rename from web/src/js/components/EventLog.jsx rename to web/src/js/components/EventLog.tsx index c07cff9bcc..50e5a70db7 100644 --- a/web/src/js/components/EventLog.jsx +++ b/web/src/js/components/EventLog.tsx @@ -1,22 +1,32 @@ import React, { Component } from "react"; -import PropTypes from "prop-types"; import { connect } from "react-redux"; -import { toggleFilter, toggleVisibility } from "../ducks/eventLog"; +import { + EventLogItem, + LogLevel, + toggleFilter, + toggleVisibility, +} from "../ducks/eventLog"; import ToggleButton from "./common/ToggleButton"; import EventList from "./EventLog/EventList"; +import { RootState } from "../ducks"; -export class PureEventLog extends Component { - static propTypes = { - filters: PropTypes.object.isRequired, - events: PropTypes.array.isRequired, - toggleFilter: PropTypes.func.isRequired, - close: PropTypes.func.isRequired, - defaultHeight: PropTypes.number, - }; +type EventLogState = { + height: number; +}; + +type EventLogProps = { + events: EventLogItem[]; + filters: { [level in LogLevel]: boolean }; + toggleFilter: (filter: LogLevel) => any; + close: () => any; + defaultHeight: number; +}; +export class PureEventLog extends Component { static defaultProps = { defaultHeight: 200, }; + private dragStart: number; constructor(props, context) { super(props, context); @@ -28,7 +38,7 @@ export class PureEventLog extends Component { this.onDragStop = this.onDragStop.bind(this); } - onDragStart(event) { + onDragStart(event: React.MouseEvent) { event.preventDefault(); this.dragStart = this.state.height + event.pageY; window.addEventListener("mousemove", this.onDragMove); @@ -36,12 +46,12 @@ export class PureEventLog extends Component { window.addEventListener("dragend", this.onDragStop); } - onDragMove(event) { + onDragMove(event: MouseEvent) { event.preventDefault(); this.setState({ height: this.dragStart - event.pageY }); } - onDragStop(event) { + onDragStop(event: MouseEvent | DragEvent) { event.preventDefault(); window.removeEventListener("mousemove", this.onDragMove); } @@ -55,16 +65,14 @@ export class PureEventLog extends Component {
Eventlog
- {["debug", "info", "web", "warn", "error"].map( - (type) => ( - toggleFilter(type)} - /> - ) - )} + {Object.values(LogLevel).map((type) => ( + toggleFilter(type)} + /> + ))}
@@ -75,12 +83,12 @@ export class PureEventLog extends Component { } export default connect( - (state) => ({ + (state: RootState) => ({ filters: state.eventLog.filters, events: state.eventLog.view, }), { close: toggleVisibility, toggleFilter: toggleFilter, - } + }, )(PureEventLog); diff --git a/web/src/js/components/EventLog/EventList.tsx b/web/src/js/components/EventLog/EventList.tsx index f52f656835..6fb05af997 100644 --- a/web/src/js/components/EventLog/EventList.tsx +++ b/web/src/js/components/EventLog/EventList.tsx @@ -1,10 +1,9 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; -import ReactDOM from "react-dom"; -import shallowEqual from "shallowequal"; -import AutoScroll from "../helpers/AutoScroll"; +import * as autoscroll from "../helpers/AutoScroll"; import { calcVScroll, VScroll } from "../helpers/VirtualScroll"; import { EventLogItem } from "../../ducks/eventLog"; +import { shallowEqual } from "react-redux"; type EventLogListProps = { events: EventLogItem[]; @@ -14,7 +13,10 @@ type EventLogListState = { vScroll: VScroll; }; -class EventLogList extends Component { +export default class EventLogList extends Component< + EventLogListProps, + EventLogListState +> { static propTypes = { events: PropTypes.array.isRequired, rowHeight: PropTypes.number, @@ -26,6 +28,8 @@ class EventLogList extends Component { heights: { [id: string]: number }; + viewport = React.createRef(); + constructor(props) { super(props); @@ -44,12 +48,19 @@ class EventLogList extends Component { window.removeEventListener("resize", this.onViewportUpdate); } - componentDidUpdate() { + getSnapshotBeforeUpdate() { + return autoscroll.isAtBottom(this.viewport); + } + + componentDidUpdate(prevProps, prevState, snapshot) { + if (snapshot) { + autoscroll.adjustScrollTop(this.viewport); + } this.onViewportUpdate(); } onViewportUpdate() { - const viewport = ReactDOM.findDOMNode(this); + const viewport = this.viewport.current!; const vScroll = calcVScroll({ itemCount: this.props.events.length, @@ -57,7 +68,7 @@ class EventLogList extends Component { viewportTop: viewport.scrollTop, viewportHeight: viewport.offsetHeight, itemHeights: this.props.events.map( - (entry) => this.heights[entry.id] + (entry) => this.heights[entry.id], ), }); @@ -81,7 +92,7 @@ class EventLogList extends Component { const { events } = this.props; return ( -
+            
                 
{events.slice(vScroll.start, vScroll.end).map((event) => (
{ } } -function LogIcon({ event }) { +function LogIcon({ event }: { event: EventLogItem }) { const icon = { web: "html5", @@ -108,5 +119,3 @@ function LogIcon({ event }) { }[event.level] || "info"; return ; } - -export default AutoScroll(EventLogList); diff --git a/web/src/js/components/FlowTable.jsx b/web/src/js/components/FlowTable.tsx similarity index 55% rename from web/src/js/components/FlowTable.jsx rename to web/src/js/components/FlowTable.tsx index 379c67e3a3..1b49639659 100644 --- a/web/src/js/components/FlowTable.jsx +++ b/web/src/js/components/FlowTable.tsx @@ -1,82 +1,91 @@ import * as React from "react"; -import PropTypes from "prop-types"; -import ReactDOM from "react-dom"; -import { connect } from "react-redux"; -import shallowEqual from "shallowequal"; -import AutoScroll from "./helpers/AutoScroll"; -import { calcVScroll } from "./helpers/VirtualScroll"; +import { connect, shallowEqual } from "react-redux"; +import * as autoscroll from "./helpers/AutoScroll"; +import { calcVScroll, VScroll } from "./helpers/VirtualScroll"; import FlowTableHead from "./FlowTable/FlowTableHead"; import FlowRow from "./FlowTable/FlowRow"; import Filt from "../filt/filt"; - -class FlowTable extends React.Component { - static propTypes = { - flows: PropTypes.array.isRequired, - rowHeight: PropTypes.number, - highlight: PropTypes.string, - selected: PropTypes.object, - }; - +import { Flow } from "../flow"; +import { RootState } from "../ducks"; + +type FlowTableProps = { + flows: Flow[]; + rowHeight: number; + highlight: string; + selected: Flow; +}; + +type FlowTableState = { + vScroll: VScroll; + viewportTop: number; +}; + +export class PureFlowTable extends React.Component< + FlowTableProps, + FlowTableState +> { static defaultProps = { rowHeight: 32, }; + private viewport = React.createRef(); + private head = React.createRef(); constructor(props, context) { super(props, context); - this.state = { vScroll: calcVScroll() }; + this.state = { + vScroll: calcVScroll(), + viewportTop: 0, + }; this.onViewportUpdate = this.onViewportUpdate.bind(this); } - UNSAFE_componentWillMount() { - window.addEventListener("resize", this.onViewportUpdate); - } - componentDidMount() { + window.addEventListener("resize", this.onViewportUpdate); this.onViewportUpdate(); } - UNSAFE_componentWillUnmount() { + componentWillUnmount() { window.removeEventListener("resize", this.onViewportUpdate); } - componentDidUpdate() { - this.onViewportUpdate(); + getSnapshotBeforeUpdate() { + return autoscroll.isAtBottom(this.viewport); + } - if (!this.shouldScrollIntoView) { - return; + componentDidUpdate(prevProps, prevState, snapshot) { + if (snapshot) { + autoscroll.adjustScrollTop(this.viewport); } + this.onViewportUpdate(); - this.shouldScrollIntoView = false; - - const { rowHeight, flows, selected } = this.props; - const viewport = ReactDOM.findDOMNode(this); - const head = ReactDOM.findDOMNode(this.refs.head); + const selectedNewFlow = + this.props.selected && this.props.selected !== prevProps.selected; + if (selectedNewFlow) { + const { rowHeight, flows, selected } = this.props; + const viewport = this.viewport.current!; + const head = this.head.current; - const headHeight = head ? head.offsetHeight : 0; + const headHeight = head ? head.offsetHeight : 0; - const rowTop = flows.indexOf(selected) * rowHeight + headHeight; - const rowBottom = rowTop + rowHeight; + const rowTop = flows.indexOf(selected) * rowHeight + headHeight; + const rowBottom = rowTop + rowHeight; - const viewportTop = viewport.scrollTop; - const viewportHeight = viewport.offsetHeight; + const viewportTop = viewport.scrollTop; + const viewportHeight = viewport.offsetHeight; - // Account for pinned thead - if (rowTop - headHeight < viewportTop) { - viewport.scrollTop = rowTop - headHeight; - } else if (rowBottom > viewportTop + viewportHeight) { - viewport.scrollTop = rowBottom - viewportHeight; - } - } - - UNSAFE_componentWillReceiveProps(nextProps) { - if (nextProps.selected && nextProps.selected !== this.props.selected) { - this.shouldScrollIntoView = true; + // Account for pinned thead + if (rowTop - headHeight < viewportTop) { + viewport.scrollTop = rowTop - headHeight; + } else if (rowBottom > viewportTop + viewportHeight) { + viewport.scrollTop = rowBottom - viewportHeight; + } + this.onViewportUpdate(); } } onViewportUpdate() { - const viewport = ReactDOM.findDOMNode(this); + const viewport = this.viewport.current!; const viewportTop = viewport.scrollTop || 0; const vScroll = calcVScroll({ @@ -93,9 +102,9 @@ class FlowTable extends React.Component { // the next rendered state may only have much lower number of rows compared to what the current // viewportHeight anticipates. To make sure that we update (almost) at once, we already constrain // the maximum viewportTop value. See https://github.com/mitmproxy/mitmproxy/pull/5658 for details. - let newViewportTop = Math.min( + const newViewportTop = Math.min( viewportTop, - vScroll.end * this.props.rowHeight + vScroll.end * this.props.rowHeight, ); this.setState({ vScroll, @@ -110,10 +119,14 @@ class FlowTable extends React.Component { const isHighlighted = highlight ? Filt.parse(highlight) : () => false; return ( -
+
@@ -136,9 +149,7 @@ class FlowTable extends React.Component { } } -export const PureFlowTable = AutoScroll(FlowTable); - -export default connect((state) => ({ +export default connect((state: RootState) => ({ flows: state.flows.view, highlight: state.flows.highlight, selected: state.flows.byId[state.flows.selected[0]], diff --git a/web/src/js/components/FlowTable/FlowColumns.tsx b/web/src/js/components/FlowTable/FlowColumns.tsx index e7d1a659ae..4d2d35f75f 100644 --- a/web/src/js/components/FlowTable/FlowColumns.tsx +++ b/web/src/js/components/FlowTable/FlowColumns.tsx @@ -1,13 +1,17 @@ -import React, { ReactElement, useState } from "react"; -import { useDispatch } from "react-redux"; +import React, { ReactElement } from "react"; +import { useAppDispatch, useAppSelector } from "../../ducks"; import classnames from "classnames"; import { canReplay, endTime, getTotalSize, - RequestUtils, - ResponseUtils, startTime, + sortFunctions, + getIcon, + mainPath, + statusCode, + getMethod, + getVersion, } from "../../flow/utils"; import { formatSize, formatTimeDelta, formatTimeStamp } from "../../utils"; import * as flowActions from "../../ducks/flows"; @@ -21,7 +25,6 @@ interface FlowColumn { (props: FlowColumnProps): JSX.Element; headerName: string; // Shown in the UI - sortKey: (flow: Flow) => any; } export const tls: FlowColumn = ({ flow }) => { @@ -31,13 +34,18 @@ export const tls: FlowColumn = ({ flow }) => { "col-tls", flow.client_conn.tls_established ? "col-tls-https" - : "col-tls-http" + : "col-tls-http", )} /> ); }; tls.headerName = ""; -tls.sortKey = (flow) => flow.type === "http" && flow.request.scheme; + +export const index: FlowColumn = ({ flow }) => { + const index = useAppSelector((state) => state.flows.listIndex[flow.id]); + return ; +}; +index.headerName = "#"; export const icon: FlowColumn = ({ flow }) => { return ( @@ -47,65 +55,6 @@ export const icon: FlowColumn = ({ flow }) => { ); }; icon.headerName = ""; -icon.sortKey = (flow) => getIcon(flow); - -const getIcon = (flow: Flow): string => { - if (flow.type !== "http") { - if (flow.client_conn.tls_version === "QUIC") { - return `resource-icon-quic`; - } - return `resource-icon-${flow.type}`; - } - if (flow.websocket) { - return "resource-icon-websocket"; - } - if (!flow.response) { - return "resource-icon-plain"; - } - - var contentType = ResponseUtils.getContentType(flow.response) || ""; - - if (flow.response.status_code === 304) { - return "resource-icon-not-modified"; - } - if (300 <= flow.response.status_code && flow.response.status_code < 400) { - return "resource-icon-redirect"; - } - if (contentType.indexOf("image") >= 0) { - return "resource-icon-image"; - } - if (contentType.indexOf("javascript") >= 0) { - return "resource-icon-js"; - } - if (contentType.indexOf("css") >= 0) { - return "resource-icon-css"; - } - if (contentType.indexOf("html") >= 0) { - return "resource-icon-document"; - } - - return "resource-icon-plain"; -}; - -const mainPath = (flow: Flow): string => { - switch (flow.type) { - case "http": - return RequestUtils.pretty_url(flow.request); - case "tcp": - case "udp": - return `${flow.client_conn.peername.join( - ":" - )} ↔ ${flow.server_conn?.address?.join(":")}`; - case "dns": - return `${flow.request.questions - .map((q) => `${q.name} ${q.type}`) - .join(", ")} = ${ - (flow.response?.answers.map((q) => q.data).join(", ") ?? - "...") || - "?" - }`; - } -}; export const path: FlowColumn = ({ flow }) => { let err; @@ -129,39 +78,16 @@ export const path: FlowColumn = ({ flow }) => { ); }; path.headerName = "Path"; -path.sortKey = (flow) => mainPath(flow); export const method: FlowColumn = ({ flow }) => ( - + ); method.headerName = "Method"; -method.sortKey = (flow) => { - switch (flow.type) { - case "http": - return flow.websocket - ? flow.client_conn.tls_established - ? "WSS" - : "WS" - : flow.request.method; - case "dns": - return flow.request.op_code; - default: - return flow.type.toUpperCase(); - } -}; export const version: FlowColumn = ({ flow }) => ( - + ); version.headerName = "Version"; -version.sortKey = (flow) => { - switch (flow.type) { - case "http": - return flow.request.http_version; - default: - return ""; - } -}; export const status: FlowColumn = ({ flow }) => { let color = "darkred"; @@ -195,31 +121,20 @@ export const status: FlowColumn = ({ flow }) => { return ( ); }; status.headerName = "Status"; -status.sortKey = (flow) => { - switch (flow.type) { - case "http": - return flow.response?.status_code; - case "dns": - return flow.response?.response_code; - default: - return undefined; - } -}; export const size: FlowColumn = ({ flow }) => { return ; }; size.headerName = "Size"; -size.sortKey = (flow) => getTotalSize(flow); export const time: FlowColumn = ({ flow }) => { - const start = startTime(flow), - end = endTime(flow); + const start = startTime(flow); + const end = endTime(flow); return ( ); }; - quickactions.headerName = ""; -quickactions.sortKey = (flow) => 0; -export default { +export const comment: FlowColumn = ({ flow }) => { + const text = flow.comment; + return ; +}; +comment.headerName = "Comment"; + +const FlowColumns: { [key in keyof typeof sortFunctions]: FlowColumn } = { + // parsed by web/gen/web_columns icon, + index, method, version, path, @@ -305,4 +206,6 @@ export default { time, timestamp, tls, + comment, }; +export default FlowColumns; diff --git a/web/src/js/components/FlowTable/FlowRow.tsx b/web/src/js/components/FlowTable/FlowRow.tsx index 84ac55a889..ddb583bf36 100644 --- a/web/src/js/components/FlowTable/FlowRow.tsx +++ b/web/src/js/components/FlowTable/FlowRow.tsx @@ -16,17 +16,17 @@ export default React.memo(function FlowRow({ selected, highlighted, }: FlowRowProps) { - const dispatch = useAppDispatch(), - displayColumnNames = useAppSelector( - (state) => state.options.web_columns - ), - className = classnames({ - selected: selected, - highlighted: highlighted, - intercepted: flow.intercepted, - "has-request": flow.type === "http" && flow.request, - "has-response": flow.type === "http" && flow.response, - }); + const dispatch = useAppDispatch(); + const displayColumnNames = useAppSelector( + (state) => state.options.web_columns, + ); + const className = classnames({ + selected: selected, + highlighted: highlighted, + intercepted: flow.intercepted, + "has-request": flow.type === "http" && flow.request, + "has-response": flow.type === "http" && flow.response, + }); const onClick = useCallback( (e) => { @@ -38,7 +38,7 @@ export default React.memo(function FlowRow({ } dispatch(select(flow.id)); }, - [flow] + [flow], ); const displayColumns = displayColumnNames diff --git a/web/src/js/components/FlowTable/FlowTableHead.tsx b/web/src/js/components/FlowTable/FlowTableHead.tsx index 9f566ce62d..584d21a58e 100644 --- a/web/src/js/components/FlowTable/FlowTableHead.tsx +++ b/web/src/js/components/FlowTable/FlowTableHead.tsx @@ -6,12 +6,12 @@ import { setSort } from "../../ducks/flows"; import { useAppDispatch, useAppSelector } from "../../ducks"; export default React.memo(function FlowTableHead() { - const dispatch = useAppDispatch(), - sortDesc = useAppSelector((state) => state.flows.sort.desc), - sortColumn = useAppSelector((state) => state.flows.sort.column), - displayColumnNames = useAppSelector( - (state) => state.options.web_columns - ); + const dispatch = useAppDispatch(); + const sortDesc = useAppSelector((state) => state.flows.sort.desc); + const sortColumn = useAppSelector((state) => state.flows.sort.column); + const displayColumnNames = useAppSelector( + (state) => state.options.web_columns, + ); const sortType = sortDesc ? "sort-desc" : "sort-asc"; const displayColumns = displayColumnNames @@ -25,7 +25,7 @@ export default React.memo(function FlowTableHead() {
{index + 1}{method.sortKey(flow)}{getMethod(flow)}{version.sortKey(flow)}{getVersion(flow)} - {status.sortKey(flow)} + {statusCode(flow)} {formatSize(getTotalSize(flow))} {start && end ? formatTimeDelta(1000 * (end - start)) : "..."} @@ -227,11 +142,6 @@ export const time: FlowColumn = ({ flow }) => { ); }; time.headerName = "Time"; -time.sortKey = (flow) => { - const start = startTime(flow), - end = endTime(flow); - return start && end && end - start; -}; export const timestamp: FlowColumn = ({ flow }) => { const start = startTime(flow); @@ -242,21 +152,9 @@ export const timestamp: FlowColumn = ({ flow }) => { ); }; timestamp.headerName = "Start time"; -timestamp.sortKey = (flow) => startTime(flow); - -const markers = { - ":red_circle:": "🔴", - ":orange_circle:": "🟠", - ":yellow_circle:": "🟡", - ":green_circle:": "🟢", - ":large_blue_circle:": "🔵", - ":purple_circle:": "🟣", - ":brown_circle:": "🟤", -}; export const quickactions: FlowColumn = ({ flow }) => { - const dispatch = useDispatch(); - let [open, setOpen] = useState(false); + const dispatch = useAppDispatch(); let resume_or_replay: ReactElement | null = null; if (flow.intercepted) { @@ -282,20 +180,23 @@ export const quickactions: FlowColumn = ({ flow }) => { } return ( - 0} - > + {resume_or_replay ?
{resume_or_replay}
: <>}
{text} @@ -34,8 +34,8 @@ export default React.memo(function FlowTableHead() { Column.name === sortColumn && sortDesc ? undefined : Column.name, - Column.name !== sortColumn ? false : !sortDesc - ) + Column.name !== sortColumn ? false : !sortDesc, + ), ) } > diff --git a/web/src/js/components/FlowView.tsx b/web/src/js/components/FlowView.tsx index 15153e9b13..9fef0290ca 100644 --- a/web/src/js/components/FlowView.tsx +++ b/web/src/js/components/FlowView.tsx @@ -9,13 +9,14 @@ import Connection from "./FlowView/Connection"; import Error from "./FlowView/Error"; import Timing from "./FlowView/Timing"; import WebSocket from "./FlowView/WebSocket"; - +import Comment from "./FlowView/Comment"; import { selectTab } from "../ducks/ui/flow"; import { useAppDispatch, useAppSelector } from "../ducks"; import { Flow } from "../flow"; import classnames from "classnames"; import TcpMessages from "./FlowView/TcpMessages"; import UdpMessages from "./FlowView/UdpMessages"; +import * as flowsActions from "../ducks/flows"; type TabProps = { flow: Flow; @@ -34,6 +35,7 @@ export const allTabs: { udpmessages: UdpMessages, dnsrequest: DnsRequest, dnsresponse: DnsResponse, + comment: Comment, }; export function tabsForFlow(flow: Flow): string[] { @@ -58,17 +60,23 @@ export function tabsForFlow(flow: Flow): string[] { if (flow.error) tabs.push("error"); tabs.push("connection"); tabs.push("timing"); + tabs.push("comment"); return tabs; } export default function FlowView() { - const dispatch = useAppDispatch(), - flow = useAppSelector( - (state) => state.flows.byId[state.flows.selected[0]] - ), - tabs = tabsForFlow(flow); - + const dispatch = useAppDispatch(); + const flow = useAppSelector( + (state) => state.flows.byId[state.flows.selected[0]], + ); let active = useAppSelector((state) => state.ui.flow.tab); + + if (flow == undefined) { + return <>; + } + + const tabs = tabsForFlow(flow); + if (tabs.indexOf(active) < 0) { if (active === "response" && flow.error) { active = "error"; @@ -83,6 +91,13 @@ export default function FlowView() { return (
diff --git a/web/src/js/components/Footer.tsx b/web/src/js/components/Footer.tsx index dfc364bf13..d9cacd8251 100644 --- a/web/src/js/components/Footer.tsx +++ b/web/src/js/components/Footer.tsx @@ -5,7 +5,7 @@ import { useAppSelector } from "../ducks"; export default function Footer() { const version = useAppSelector((state) => state.backendState.version); - let { + const { mode, intercept, showhost, diff --git a/web/src/js/components/Header.tsx b/web/src/js/components/Header.tsx index c25c269679..fe06472207 100644 --- a/web/src/js/components/Header.tsx +++ b/web/src/js/components/Header.tsx @@ -1,59 +1,82 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import classnames from "classnames"; -import StartMenu from "./Header/StartMenu"; -import OptionMenu from "./Header/OptionMenu"; import FileMenu from "./Header/FileMenu"; -import FlowMenu from "./Header/FlowMenu"; import ConnectionIndicator from "./Header/ConnectionIndicator"; import HideInStatic from "./common/HideInStatic"; -import { useAppSelector } from "../ducks"; - -interface Menu { - (): JSX.Element; +import CaptureMenu from "./Header/CaptureMenu"; +import { useAppDispatch, useAppSelector } from "../ducks"; +import FlowListMenu from "./Header/FlowListMenu"; +import OptionMenu from "./Header/OptionMenu"; +import FlowMenu from "./Header/FlowMenu"; +import { Menu } from "./ProxyApp"; +import { shallowEqual } from "react-redux"; +import { Tab, setCurrent } from "../ducks/ui/tabs"; - title: string; -} +const tabs: { [key in Tab]: Menu } = { + [Tab.Capture]: CaptureMenu, + [Tab.FlowList]: FlowListMenu, + [Tab.Options]: OptionMenu, + [Tab.Flow]: FlowMenu, +}; export default function Header() { - const selectedFlows = useAppSelector((state) => - state.flows.selected.filter((id) => id in state.flows.byId) - ), - [ActiveMenu, setActiveMenu] = useState
(() => StartMenu), - [wasFlowSelected, setWasFlowSelected] = useState(false); + const dispatch = useAppDispatch(); + const currentTab = useAppSelector((state) => state.ui.tabs.current); + const selectedFlows = useAppSelector( + (state) => state.flows.selected.filter((id) => id in state.flows.byId), + shallowEqual, + ); + const [wasFlowSelected, setWasFlowSelected] = useState(false); + const hasFlows = useAppSelector((state) => state.flows.list.length > 0); + const isInitialTab = useAppSelector((state) => state.ui.tabs.isInitial); - let entries: Menu[] = [StartMenu, OptionMenu]; + const entries: Tab[] = [Tab.Capture, Tab.FlowList, Tab.Options]; if (selectedFlows.length > 0) { - if (!wasFlowSelected) { - setActiveMenu(() => FlowMenu); - setWasFlowSelected(true); - } - entries.push(FlowMenu); - } else { - if (wasFlowSelected) { - setWasFlowSelected(false); + entries.push(Tab.Flow); + } + + // Switch to "Flow List" when the first flow appears. + useEffect(() => { + if (hasFlows && isInitialTab) { + dispatch(setCurrent(Tab.FlowList)); } - if (ActiveMenu === FlowMenu) { - setActiveMenu(() => StartMenu); + }, [hasFlows]); + + // Switch to "Flow" tab if we just selected a new flow. + useEffect(() => { + if (selectedFlows.length > 0 && !wasFlowSelected) { + // User just clicked on a flow without having previously selected one. + dispatch(setCurrent(Tab.Flow)); + setWasFlowSelected(true); + } else if (selectedFlows.length === 0) { + if (wasFlowSelected) { + setWasFlowSelected(false); + } + if (currentTab === Tab.Flow) { + dispatch(setCurrent(Tab.FlowList)); + } } - } + }, [selectedFlows, wasFlowSelected, currentTab]); - function handleClick(active: Menu, e) { + function handleClick(tab: Tab, e: React.MouseEvent) { e.preventDefault(); - setActiveMenu(() => active); + dispatch(setCurrent(tab)); } + const ActiveMenu = tabs[currentTab]; + return (